Bläddra i källkod

d01 Обновление вендоринга

SVI 3 år sedan
förälder
incheckning
6c05603cee
72 ändrade filer med 14081 tillägg och 0 borttagningar
  1. 502 0
      vendor/github.com/visualfc/atk/LICENSE
  2. 228 0
      vendor/github.com/visualfc/atk/tk/action.go
  3. 237 0
      vendor/github.com/visualfc/atk/tk/basewidget.go
  4. 171 0
      vendor/github.com/visualfc/atk/tk/button.go
  5. 329 0
      vendor/github.com/visualfc/atk/tk/canvas.go
  6. 182 0
      vendor/github.com/visualfc/atk/tk/checkbox.go
  7. 20 0
      vendor/github.com/visualfc/atk/tk/clipboard.go
  8. 222 0
      vendor/github.com/visualfc/atk/tk/combobox.go
  9. 92 0
      vendor/github.com/visualfc/atk/tk/command.go
  10. 222 0
      vendor/github.com/visualfc/atk/tk/dialog.go
  11. 311 0
      vendor/github.com/visualfc/atk/tk/entry.go
  12. 13 0
      vendor/github.com/visualfc/atk/tk/error.go
  13. 351 0
      vendor/github.com/visualfc/atk/tk/event.go
  14. 272 0
      vendor/github.com/visualfc/atk/tk/font.go
  15. 133 0
      vendor/github.com/visualfc/atk/tk/frame.go
  16. 167 0
      vendor/github.com/visualfc/atk/tk/grid.go
  17. 71 0
      vendor/github.com/visualfc/atk/tk/gridlayout.go
  18. 121 0
      vendor/github.com/visualfc/atk/tk/ids.go
  19. 176 0
      vendor/github.com/visualfc/atk/tk/image.go
  20. 22 0
      vendor/github.com/visualfc/atk/tk/interp/cbytes_go16_unix.go
  21. 15 0
      vendor/github.com/visualfc/atk/tk/interp/cbytes_unix.go
  22. 281 0
      vendor/github.com/visualfc/atk/tk/interp/interp.go
  23. 756 0
      vendor/github.com/visualfc/atk/tk/interp/interp_unix.go
  24. 861 0
      vendor/github.com/visualfc/atk/tk/interp/interp_windows.go
  25. 13 0
      vendor/github.com/visualfc/atk/tk/interp/syncmap.go
  26. 13 0
      vendor/github.com/visualfc/atk/tk/interp/syncmap_18.go
  27. 340 0
      vendor/github.com/visualfc/atk/tk/interp/zinterp_windows.go
  28. 266 0
      vendor/github.com/visualfc/atk/tk/label.go
  29. 160 0
      vendor/github.com/visualfc/atk/tk/labelframe.go
  30. 148 0
      vendor/github.com/visualfc/atk/tk/layout.go
  31. 389 0
      vendor/github.com/visualfc/atk/tk/listbox.go
  32. 341 0
      vendor/github.com/visualfc/atk/tk/menu.go
  33. 186 0
      vendor/github.com/visualfc/atk/tk/menubutton.go
  34. 512 0
      vendor/github.com/visualfc/atk/tk/misc.go
  35. 257 0
      vendor/github.com/visualfc/atk/tk/notebook.go
  36. 148 0
      vendor/github.com/visualfc/atk/tk/pack.go
  37. 196 0
      vendor/github.com/visualfc/atk/tk/packlayout.go
  38. 83 0
      vendor/github.com/visualfc/atk/tk/paned.go
  39. 101 0
      vendor/github.com/visualfc/atk/tk/place.go
  40. 93 0
      vendor/github.com/visualfc/atk/tk/placeframe.go
  41. 138 0
      vendor/github.com/visualfc/atk/tk/progressbar.go
  42. 185 0
      vendor/github.com/visualfc/atk/tk/radiobutton.go
  43. 165 0
      vendor/github.com/visualfc/atk/tk/radiobutton_group.go
  44. BIN
      vendor/github.com/visualfc/atk/tk/rsrc_windows_386.syso
  45. BIN
      vendor/github.com/visualfc/atk/tk/rsrc_windows_amd64.syso
  46. 134 0
      vendor/github.com/visualfc/atk/tk/scale.go
  47. 88 0
      vendor/github.com/visualfc/atk/tk/scrollbar.go
  48. 51 0
      vendor/github.com/visualfc/atk/tk/scrolllayout.go
  49. 61 0
      vendor/github.com/visualfc/atk/tk/separator.go
  50. 180 0
      vendor/github.com/visualfc/atk/tk/spinbox.go
  51. 631 0
      vendor/github.com/visualfc/atk/tk/text.go
  52. 30 0
      vendor/github.com/visualfc/atk/tk/theme.go
  53. 55 0
      vendor/github.com/visualfc/atk/tk/theme_ttk.go
  54. 266 0
      vendor/github.com/visualfc/atk/tk/tk.go
  55. 17 0
      vendor/github.com/visualfc/atk/tk/tk.manifest
  56. 211 0
      vendor/github.com/visualfc/atk/tk/treeitem.go
  57. 557 0
      vendor/github.com/visualfc/atk/tk/treeview.go
  58. 47 0
      vendor/github.com/visualfc/atk/tk/utils.go
  59. 169 0
      vendor/github.com/visualfc/atk/tk/widget.go
  60. 91 0
      vendor/github.com/visualfc/atk/tk/widget_attr.go
  61. 927 0
      vendor/github.com/visualfc/atk/tk/widget_meta.go
  62. 178 0
      vendor/github.com/visualfc/atk/tk/widget_type.go
  63. 417 0
      vendor/github.com/visualfc/atk/tk/window.go
  64. 15 0
      vendor/github.com/visualfc/atk/tk/window_darwin.go
  65. 17 0
      vendor/github.com/visualfc/atk/tk/window_linux.go
  66. 16 0
      vendor/github.com/visualfc/atk/tk/window_windows.go
  67. 3 0
      vendor/golang.org/x/sync/AUTHORS
  68. 3 0
      vendor/golang.org/x/sync/CONTRIBUTORS
  69. 27 0
      vendor/golang.org/x/sync/LICENSE
  70. 22 0
      vendor/golang.org/x/sync/PATENTS
  71. 372 0
      vendor/golang.org/x/sync/syncmap/map.go
  72. 7 0
      vendor/modules.txt

+ 502 - 0
vendor/github.com/visualfc/atk/LICENSE

@@ -0,0 +1,502 @@
+                   GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+(This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.)
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+                  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                            NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    {description}
+    Copyright (C) 2017 七叶
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  {signature of Ty Coon}, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!

+ 228 - 0
vendor/github.com/visualfc/atk/tk/action.go

@@ -0,0 +1,228 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+)
+
+type Action struct {
+	actid   string
+	label   string
+	checkid string
+	groupid string
+	radioid string
+	command *Command
+	data    interface{}
+}
+
+func (a *Action) String() string {
+	if a.actid == "" {
+		return "Separator"
+	} else if a.groupid != "" {
+		return fmt.Sprintf("RadioAction{%v}", a.label)
+	} else if a.checkid != "" {
+		return fmt.Sprintf("CheckAction{%v}", a.label)
+	} else {
+		return fmt.Sprintf("Action{%v}", a.label)
+	}
+}
+
+func (a *Action) IsSeparator() bool {
+	return a.actid == ""
+}
+
+func (a *Action) IsRadioAction() bool {
+	return a.groupid != ""
+}
+
+func (a *Action) IsCheckAction() bool {
+	return a.checkid != ""
+}
+
+func (a *Action) SetChecked(b bool) {
+	if a.groupid != "" {
+		eval(fmt.Sprintf("set %v {%v}", a.groupid, a.radioid))
+	} else if a.checkid != "" {
+		eval(fmt.Sprintf("set %v {%v}", a.checkid, boolToInt(b)))
+	}
+}
+
+func (a *Action) IsChecked() bool {
+	if a.groupid != "" {
+		r, _ := evalAsString(fmt.Sprintf("set %v", a.groupid))
+		return r == a.radioid
+	} else if a.checkid != "" {
+		b, _ := evalAsBool(fmt.Sprintf("set %v", a.checkid))
+		return b
+	}
+	return false
+}
+
+func (a *Action) Label() string {
+	return a.label
+}
+
+func (a *Action) SetData(data interface{}) {
+	a.data = data
+}
+
+func (a *Action) Data() interface{} {
+	return a.data
+}
+
+func (a *Action) Invoke() {
+	a.command.Invoke()
+}
+
+func (a *Action) OnCommand(fn func()) error {
+	if fn == nil {
+		return ErrInvalid
+	}
+	a.command.Bind(fn)
+	return nil
+}
+
+func NewAction(label string) *Action {
+	act := &Action{}
+	act.label = label
+	act.actid = makeActionId()
+	act.command = &Command{}
+	mainInterp.CreateAction(act.actid, func([]string) {
+		act.command.Invoke()
+	})
+	return act
+}
+
+func NewActionEx(label string, cmd func()) *Action {
+	act := NewAction(label)
+	act.OnCommand(cmd)
+	return act
+}
+
+func NewCheckAction(label string) *Action {
+	act := NewAction(label)
+	id := makeNamedId("atk_checkaction")
+	evalSetValue(id, "0")
+	act.checkid = id
+	return act
+}
+
+func NewCheckActionEx(label string, cmd func()) *Action {
+	act := NewCheckAction(label)
+	act.OnCommand(cmd)
+	return act
+}
+
+func NewRadioAction(group *ActionGroup, label string) *Action {
+	return group.AddNewRadioAction(label)
+}
+
+func NewSeparatorAction() *Action {
+	action := &Action{}
+	return action
+}
+
+type ActionGroup struct {
+	groupid        string
+	actions        []*Action
+	fnRadioCommand func()
+}
+
+func NewActionGroup() *ActionGroup {
+	id := makeNamedId("atk_actiongroup")
+	evalSetValue(id, "")
+	return &ActionGroup{id, nil, nil}
+}
+
+func (a *ActionGroup) findAction(act *Action) bool {
+	for _, v := range a.actions {
+		if v == act {
+			return true
+		}
+	}
+	return false
+}
+
+func (a *ActionGroup) radioCommand() {
+	if a.fnRadioCommand != nil {
+		a.fnRadioCommand()
+	}
+}
+
+func (a *ActionGroup) AddRadioAction(act *Action) error {
+	if a.findAction(act) {
+		return ErrExist
+	}
+	act.groupid = a.groupid
+	act.radioid = makeNamedId("atk_radioaction")
+	act.OnCommand(a.radioCommand)
+	a.actions = append(a.actions, act)
+	return nil
+}
+
+func (a *ActionGroup) AddNewRadioAction(label string) *Action {
+	act := NewAction(label)
+	a.AddRadioAction(act)
+	return act
+}
+
+func (a *ActionGroup) OnCommand(fn func()) {
+	a.fnRadioCommand = fn
+}
+
+func (a *ActionGroup) checkedValue() string {
+	r, _ := evalAsStringEx(fmt.Sprintf("set %v", a.groupid), false)
+	return r
+}
+
+func (a *ActionGroup) SetCheckedIndex(index int) error {
+	if index < 0 || index > len(a.actions) {
+		return ErrInvalid
+	}
+	a.actions[index].SetChecked(true)
+	return nil
+}
+
+func (a *ActionGroup) SetCheckedAction(act *Action) error {
+	if act == nil {
+		return ErrInvalid
+	}
+	for _, v := range a.actions {
+		if v == act {
+			act.SetChecked(true)
+			return nil
+		}
+	}
+	return ErrNotExist
+}
+
+func (a *ActionGroup) CheckedActionIndex() int {
+	s := a.checkedValue()
+	if s == "" {
+		return -1
+	}
+	for n, act := range a.actions {
+		if act.radioid == s {
+			return n
+		}
+	}
+	return -1
+}
+
+func (a *ActionGroup) CheckedAction() *Action {
+	s := a.checkedValue()
+	if s == "" {
+		return nil
+	}
+	for _, act := range a.actions {
+		if act.radioid == s {
+			return act
+		}
+	}
+	return nil
+}
+
+func (a *ActionGroup) Actions() []*Action {
+	return a.actions
+}

+ 237 - 0
vendor/github.com/visualfc/atk/tk/basewidget.go

@@ -0,0 +1,237 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+	"strings"
+)
+
+var _ Widget = &BaseWidget{}
+
+type BaseWidget struct {
+	id   string
+	info *WidgetInfo
+}
+
+func (w *BaseWidget) String() string {
+	iw := globalWidgetMap[w.id]
+	if iw != nil {
+		return fmt.Sprintf("%v{%v}", iw.TypeName(), w.id)
+	} else {
+		return fmt.Sprintf("Invalid{%v}", w.id)
+	}
+}
+
+func (w *BaseWidget) Id() string {
+	return w.id
+}
+
+func (w *BaseWidget) Info() *WidgetInfo {
+	return w.info
+}
+
+func (w *BaseWidget) Type() WidgetType {
+	if w.info != nil {
+		return w.info.Type
+	}
+	return WidgetTypeNone
+}
+
+func (w *BaseWidget) TypeName() string {
+	if w.info != nil {
+		return w.info.TypeName
+	}
+	return "Invalid"
+}
+
+func (w *BaseWidget) Parent() Widget {
+	return ParentOfWidget(w)
+}
+
+func (w *BaseWidget) Children() []Widget {
+	return ChildrenOfWidget(w)
+}
+
+func (w *BaseWidget) IsValid() bool {
+	return IsValidWidget(w)
+}
+
+func (w *BaseWidget) Destroy() error {
+	return DestroyWidget(w)
+}
+
+func (w *BaseWidget) DestroyChildren() error {
+	if !IsValidWidget(w) {
+		return ErrInvalid
+	}
+	for _, child := range w.Children() {
+		DestroyWidget(child)
+	}
+	return nil
+}
+
+func (w *BaseWidget) NativeAttribute(key string) string {
+	if !IsValidWidget(w) {
+		return ""
+	}
+	if !w.info.MetaClass.HasAttribute(key) {
+		return ""
+	}
+	r, _ := evalAsString(fmt.Sprintf("%v cget -%v", w.id, key))
+	return r
+}
+
+func (w *BaseWidget) NativeAttributes(keys ...string) (attributes []NativeAttr) {
+	if !IsValidWidget(w) {
+		return nil
+	}
+	if keys == nil {
+		for _, key := range w.info.MetaClass.Attributes {
+			r, _ := evalAsString(fmt.Sprintf("%v cget -%v", w.id, key))
+			attributes = append(attributes, NativeAttr{key, r})
+		}
+	} else {
+		for _, key := range keys {
+			if w.info.MetaClass.HasAttribute(key) {
+				r, _ := evalAsString(fmt.Sprintf("%v cget -%v", w.id, key))
+				attributes = append(attributes, NativeAttr{key, r})
+			}
+		}
+	}
+	return
+}
+
+func (w *BaseWidget) SetNativeAttribute(key string, value string) error {
+	return w.SetNativeAttributes([]NativeAttr{NativeAttr{key, value}}...)
+}
+
+func (w *BaseWidget) SetNativeAttributes(attributes ...NativeAttr) error {
+	if !IsValidWidget(w) {
+		return ErrInvalid
+	}
+	var attrList []string
+	for _, attr := range attributes {
+		if !w.info.MetaClass.HasAttribute(attr.Key) {
+			continue
+		}
+		pname := "atk_tmp_" + attr.Key
+		setObjText(pname, attr.Value)
+		attrList = append(attrList, fmt.Sprintf("-%v $%v", attr.Key, pname))
+	}
+	if len(attrList) > 0 {
+		return eval(fmt.Sprintf("%v configure %v", w.id, strings.Join(attrList, " ")))
+	}
+	return nil
+}
+
+func (w *BaseWidget) SetAttributes(attributes ...*WidgetAttr) error {
+	if !IsValidWidget(w) {
+		return ErrInvalid
+	}
+	extra := buildWidgetAttributeScript(w.info.MetaClass, w.info.IsTtk, attributes)
+	if len(extra) > 0 {
+		return eval(fmt.Sprintf("%v configure %v", w.id, extra))
+	}
+	return nil
+}
+
+func (w *BaseWidget) BindEvent(event string, fn func(e *Event)) error {
+	return BindEvent(w.id, event, fn)
+}
+
+func (w *BaseWidget) BindKeyEvent(fn func(e *KeyEvent)) error {
+	return BindKeyEventEx(w.id, fn, nil)
+}
+
+func (w *BaseWidget) BindKeyEventEx(fnPress func(e *KeyEvent), fnRelease func(e *KeyEvent)) error {
+	return BindKeyEventEx(w.id, fnPress, fnRelease)
+}
+
+func (w *BaseWidget) BindInfo() []string {
+	return BindInfo(w.id)
+}
+
+func (w *BaseWidget) ClearBind(event string) error {
+	return ClearBindEvent(w.id, event)
+}
+
+func (w *BaseWidget) Lower(below Widget) error {
+	script := fmt.Sprintf("lower %v", w.id)
+	if IsValidWidget(below) {
+		script += " " + below.Id()
+	}
+	return eval(script)
+}
+
+func (w *BaseWidget) Raise(above Widget) error {
+	script := fmt.Sprintf("raise %v", w.id)
+	if IsValidWidget(above) {
+		script += " " + above.Id()
+	}
+	return eval(script)
+}
+
+func (w *BaseWidget) SetGrab() error {
+	return eval(fmt.Sprintf("grab set %v", w.id))
+}
+
+func (w *BaseWidget) ReleaseGrab() error {
+	return eval(fmt.Sprintf("grab release %v", w.id))
+}
+
+func (w *BaseWidget) IsGrab() bool {
+	id, err := evalAsString("grab current")
+	if err != nil || id == "" {
+		return false
+	}
+	return w.id == id
+}
+
+func (w *BaseWidget) SetFocus() error {
+	return eval(fmt.Sprintf("focus %v", w.id))
+}
+
+func (w *BaseWidget) IsFocus() bool {
+	id, err := evalAsString("focus")
+	if err != nil || id == "" {
+		return false
+	}
+	return w.id == id
+}
+
+func (w *BaseWidget) FocusNextWidget() Widget {
+	id, err := evalAsString("tk_focusNext " + w.id)
+	if err != nil || id == "" {
+		return nil
+	}
+	return FindWidget(id)
+}
+
+func (w *BaseWidget) FocusPrevWidget() Widget {
+	id, err := evalAsString("tk_focusPrev " + w.id)
+	if err != nil || id == "" {
+		return nil
+	}
+	return FindWidget(id)
+}
+
+func SetFocusFollowsMouse() error {
+	return eval("tk_focusFollowsMouse")
+}
+
+func FocusWidget() Widget {
+	id, err := evalAsString("focus")
+	if err != nil || id == "" {
+		return nil
+	}
+	return FindWidget(id)
+}
+
+func GrabWidget() Widget {
+	id, err := evalAsString("grab current")
+	if err != nil || id == "" {
+		return nil
+	}
+	return FindWidget(id)
+}

+ 171 - 0
vendor/github.com/visualfc/atk/tk/button.go

@@ -0,0 +1,171 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import "fmt"
+
+// button
+type Button struct {
+	BaseWidget
+	command *Command
+}
+
+func NewButton(parent Widget, text string, attributes ...*WidgetAttr) *Button {
+	theme := checkInitUseTheme(attributes)
+	iid := makeNamedWidgetId(parent, "atk_button")
+	attributes = append(attributes, &WidgetAttr{"text", text})
+	info := CreateWidgetInfo(iid, WidgetTypeButton, theme, attributes)
+	if info == nil {
+		return nil
+	}
+	w := &Button{}
+	w.id = iid
+	w.info = info
+	RegisterWidget(w)
+	return w
+}
+
+func (w *Button) Attach(id string) error {
+	info, err := CheckWidgetInfo(id, WidgetTypeButton)
+	if err != nil {
+		return err
+	}
+	w.id = id
+	w.info = info
+	RegisterWidget(w)
+	return nil
+}
+
+func (w *Button) SetText(text string) error {
+	setObjText("atk_tmp_text", text)
+	return eval(fmt.Sprintf("%v configure -text $atk_tmp_text", w.id))
+}
+
+func (w *Button) Text() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -text", w.id))
+	return r
+}
+
+func (w *Button) SetWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -width {%v}", w.id, width))
+}
+
+func (w *Button) Width() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -width", w.id))
+	return r
+}
+
+func (w *Button) SetImage(image *Image) error {
+	if image == nil {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("%v configure -image {%v}", w.id, image.Id()))
+}
+
+func (w *Button) Image() *Image {
+	r, err := evalAsString(fmt.Sprintf("%v cget -image", w.id))
+	return parserImageResult(r, err)
+}
+
+func (w *Button) SetCompound(compound Compound) error {
+	return eval(fmt.Sprintf("%v configure -compound {%v}", w.id, compound))
+}
+
+func (w *Button) Compound() Compound {
+	r, err := evalAsString(fmt.Sprintf("%v cget -compound", w.id))
+	return parserCompoundResult(r, err)
+}
+
+func (w *Button) SetPaddingN(padx int, pady int) error {
+	if w.info.IsTtk {
+		return eval(fmt.Sprintf("%v configure -padding {%v %v}", w.id, padx, pady))
+	}
+	return eval(fmt.Sprintf("%v configure -padx {%v} -pady {%v}", w.id, padx, pady))
+}
+
+func (w *Button) PaddingN() (int, int) {
+	var r string
+	var err error
+	if w.info.IsTtk {
+		r, err = evalAsString(fmt.Sprintf("%v cget -padding", w.id))
+	} else {
+		r1, _ := evalAsString(fmt.Sprintf("%v cget -padx", w.id))
+		r2, _ := evalAsString(fmt.Sprintf("%v cget -pady", w.id))
+		r = r1 + " " + r2
+	}
+	return parserPaddingResult(r, err)
+}
+
+func (w *Button) SetPadding(pad Pad) error {
+	return w.SetPaddingN(pad.X, pad.Y)
+}
+
+func (w *Button) Padding() Pad {
+	x, y := w.PaddingN()
+	return Pad{x, y}
+}
+
+func (w *Button) SetState(state State) error {
+	return eval(fmt.Sprintf("%v configure -state {%v}", w.id, state))
+}
+
+func (w *Button) State() State {
+	r, err := evalAsString(fmt.Sprintf("%v cget -state", w.id))
+	return parserStateResult(r, err)
+}
+
+func (w *Button) SetTakeFocus(takefocus bool) error {
+	return eval(fmt.Sprintf("%v configure -takefocus {%v}", w.id, boolToInt(takefocus)))
+}
+
+func (w *Button) IsTakeFocus() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -takefocus", w.id))
+	return r
+}
+
+func (w *Button) OnCommand(fn func()) error {
+	if fn == nil {
+		return ErrInvalid
+	}
+	if w.command == nil {
+		w.command = &Command{}
+		bindCommand(w.id, "command", w.command.Invoke)
+	}
+	w.command.Bind(fn)
+	return nil
+}
+
+func (w *Button) Invoke() {
+	eval(fmt.Sprintf("%v invoke", w.id))
+}
+
+func ButtonAttrText(text string) *WidgetAttr {
+	return &WidgetAttr{"text", text}
+}
+
+func ButtonAttrWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"width", width}
+}
+
+func ButtonAttrImage(image *Image) *WidgetAttr {
+	if image == nil {
+		return nil
+	}
+	return &WidgetAttr{"image", image.Id()}
+}
+
+func ButtonAttrCompound(compound Compound) *WidgetAttr {
+	return &WidgetAttr{"compound", compound}
+}
+
+func ButtonAttrPadding(padding Pad) *WidgetAttr {
+	return &WidgetAttr{"padding", padding}
+}
+
+func ButtonAttrState(state State) *WidgetAttr {
+	return &WidgetAttr{"state", state}
+}
+
+func ButtonAttrTakeFocus(takefocus bool) *WidgetAttr {
+	return &WidgetAttr{"takefocus", boolToInt(takefocus)}
+}

+ 329 - 0
vendor/github.com/visualfc/atk/tk/canvas.go

@@ -0,0 +1,329 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import "fmt"
+
+// Create and manipulate 'canvas' hypergraphics drawing surface widgets
+type Canvas struct {
+	BaseWidget
+	xscrollcommand *CommandEx
+	yscrollcommand *CommandEx
+}
+
+func NewCanvas(parent Widget, attributes ...*WidgetAttr) *Canvas {
+	theme := checkInitUseTheme(attributes)
+	iid := makeNamedWidgetId(parent, "atk_canvas")
+	info := CreateWidgetInfo(iid, WidgetTypeCanvas, theme, attributes)
+	if info == nil {
+		return nil
+	}
+	w := &Canvas{}
+	w.id = iid
+	w.info = info
+	RegisterWidget(w)
+	return w
+}
+
+func (w *Canvas) Attach(id string) error {
+	info, err := CheckWidgetInfo(id, WidgetTypeCanvas)
+	if err != nil {
+		return err
+	}
+	w.id = id
+	w.info = info
+	RegisterWidget(w)
+	return nil
+}
+
+func (w *Canvas) SetBackground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -background $atk_tmp_text", w.id))
+}
+
+func (w *Canvas) Background() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -background", w.id))
+	return r
+}
+
+func (w *Canvas) SetBorderWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -borderwidth {%v}", w.id, width))
+}
+
+func (w *Canvas) BorderWidth() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -borderwidth", w.id))
+	return r
+}
+
+func (w *Canvas) SetHighlightBackground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -highlightbackground $atk_tmp_text", w.id))
+}
+
+func (w *Canvas) HighlightBackground() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -highlightbackground", w.id))
+	return r
+}
+
+func (w *Canvas) SetHighlightColor(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -highlightcolor $atk_tmp_text", w.id))
+}
+
+func (w *Canvas) HighlightColor() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -highlightcolor", w.id))
+	return r
+}
+
+func (w *Canvas) SetHighlightthickness(width int) error {
+	return eval(fmt.Sprintf("%v configure -highlightthickness {%v}", w.id, width))
+}
+
+func (w *Canvas) Highlightthickness() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -highlightthickness", w.id))
+	return r
+}
+
+func (w *Canvas) SetInsertBackground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -insertbackground $atk_tmp_text", w.id))
+}
+
+func (w *Canvas) InsertBackground() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -insertbackground", w.id))
+	return r
+}
+
+func (w *Canvas) SetInsertBorderWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -insertborderwidth {%v}", w.id, width))
+}
+
+func (w *Canvas) InsertBorderWidth() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -insertborderwidth", w.id))
+	return r
+}
+
+func (w *Canvas) SetInsertOffTime(offtime int) error {
+	return eval(fmt.Sprintf("%v configure -insertofftime {%v}", w.id, offtime))
+}
+
+func (w *Canvas) InsertOffTime() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -insertofftime", w.id))
+	return r
+}
+
+func (w *Canvas) SetInsertOnTime(ontime int) error {
+	return eval(fmt.Sprintf("%v configure -insertontime {%v}", w.id, ontime))
+}
+
+func (w *Canvas) InsertOnTime() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -insertontime", w.id))
+	return r
+}
+
+func (w *Canvas) SetInsertWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -insertwidth {%v}", w.id, width))
+}
+
+func (w *Canvas) InsertWidth() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -insertwidth", w.id))
+	return r
+}
+
+func (w *Canvas) SetReliefStyle(relief ReliefStyle) error {
+	return eval(fmt.Sprintf("%v configure -relief {%v}", w.id, relief))
+}
+
+func (w *Canvas) ReliefStyle() ReliefStyle {
+	r, err := evalAsString(fmt.Sprintf("%v cget -relief", w.id))
+	return parserReliefStyleResult(r, err)
+}
+
+func (w *Canvas) SetSelectBackground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -selectbackground $atk_tmp_text", w.id))
+}
+
+func (w *Canvas) SelectBackground() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -selectbackground", w.id))
+	return r
+}
+
+func (w *Canvas) SetSelectborderwidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -selectborderwidth {%v}", w.id, width))
+}
+
+func (w *Canvas) Selectborderwidth() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -selectborderwidth", w.id))
+	return r
+}
+
+func (w *Canvas) SetSelectforeground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -selectforeground $atk_tmp_text", w.id))
+}
+
+func (w *Canvas) Selectforeground() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -selectforeground", w.id))
+	return r
+}
+
+func (w *Canvas) SetTakeFocus(takefocus bool) error {
+	return eval(fmt.Sprintf("%v configure -takefocus {%v}", w.id, boolToInt(takefocus)))
+}
+
+func (w *Canvas) IsTakeFocus() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -takefocus", w.id))
+	return r
+}
+
+func (w *Canvas) SetCloseEnough(closeenough float64) error {
+	return eval(fmt.Sprintf("%v configure -closeenough {%v}", w.id, closeenough))
+}
+
+func (w *Canvas) CloseEnough() float64 {
+	r, _ := evalAsFloat64(fmt.Sprintf("%v cget -closeenough", w.id))
+	return r
+}
+
+func (w *Canvas) SetConfine(confine bool) error {
+	return eval(fmt.Sprintf("%v configure -confine {%v}", w.id, boolToInt(confine)))
+}
+
+func (w *Canvas) IsConfine() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -confine", w.id))
+	return r
+}
+
+func (w *Canvas) SetWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -width {%v}", w.id, width))
+}
+
+func (w *Canvas) Width() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -width", w.id))
+	return r
+}
+
+func (w *Canvas) SetHeight(height int) error {
+	return eval(fmt.Sprintf("%v configure -height {%v}", w.id, height))
+}
+
+func (w *Canvas) Height() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -height", w.id))
+	return r
+}
+
+func (w *Canvas) SetState(state State) error {
+	return eval(fmt.Sprintf("%v configure -state {%v}", w.id, state))
+}
+
+func (w *Canvas) State() State {
+	r, err := evalAsString(fmt.Sprintf("%v cget -state", w.id))
+	return parserStateResult(r, err)
+}
+
+func (w *Canvas) SetXScrollIncrement(value int) error {
+	return eval(fmt.Sprintf("%v configure -xscrollincrement {%v}", w.id, value))
+}
+
+func (w *Canvas) XScrollIncrement() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -xscrollincrement", w.id))
+	return r
+}
+
+func (w *Canvas) SetYScrollIncrement(value int) error {
+	return eval(fmt.Sprintf("%v configure -yscrollincrement {%v}", w.id, value))
+}
+
+func (w *Canvas) YScrollIncrement() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -yscrollincrement", w.id))
+	return r
+}
+
+func CanvasAttrBackground(color string) *WidgetAttr {
+	return &WidgetAttr{"background", color}
+}
+
+func CanvasAttrBorderWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"borderwidth", width}
+}
+
+func CanvasAttrHighlightBackground(color string) *WidgetAttr {
+	return &WidgetAttr{"highlightbackground", color}
+}
+
+func CanvasAttrHighlightColor(color string) *WidgetAttr {
+	return &WidgetAttr{"highlightcolor", color}
+}
+
+func CanvasAttrHighlightthickness(width int) *WidgetAttr {
+	return &WidgetAttr{"highlightthickness", width}
+}
+
+func CanvasAttrInsertBackground(color string) *WidgetAttr {
+	return &WidgetAttr{"insertbackground", color}
+}
+
+func CanvasAttrInsertBorderWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"insertborderwidth", width}
+}
+
+func CanvasAttrInsertOffTime(offtime int) *WidgetAttr {
+	return &WidgetAttr{"insertofftime", offtime}
+}
+
+func CanvasAttrInsertOnTime(ontime int) *WidgetAttr {
+	return &WidgetAttr{"insertontime", ontime}
+}
+
+func CanvasAttrInsertWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"insertwidth", width}
+}
+
+func CanvasAttrReliefStyle(relief ReliefStyle) *WidgetAttr {
+	return &WidgetAttr{"relief", relief}
+}
+
+func CanvasAttrSelectBackground(color string) *WidgetAttr {
+	return &WidgetAttr{"selectbackground", color}
+}
+
+func CanvasAttrSelectborderwidth(width int) *WidgetAttr {
+	return &WidgetAttr{"selectborderwidth", width}
+}
+
+func CanvasAttrSelectforeground(color string) *WidgetAttr {
+	return &WidgetAttr{"selectforeground", color}
+}
+
+func CanvasAttrTakeFocus(takefocus bool) *WidgetAttr {
+	return &WidgetAttr{"takefocus", boolToInt(takefocus)}
+}
+
+func CanvasAttrCloseEnough(closeenough float64) *WidgetAttr {
+	return &WidgetAttr{"closeenough", closeenough}
+}
+
+func CanvasAttrConfine(confine bool) *WidgetAttr {
+	return &WidgetAttr{"confine", boolToInt(confine)}
+}
+
+func CanvasAttrWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"width", width}
+}
+
+func CanvasAttrHeight(height int) *WidgetAttr {
+	return &WidgetAttr{"height", height}
+}
+
+func CanvasAttrState(state State) *WidgetAttr {
+	return &WidgetAttr{"state", state}
+}
+
+func CanvasAttrXScrollIncrement(value int) *WidgetAttr {
+	return &WidgetAttr{"xscrollincrement", value}
+}
+
+func CanvasAttrYScrollIncrement(value int) *WidgetAttr {
+	return &WidgetAttr{"yscrollincrement", value}
+}

+ 182 - 0
vendor/github.com/visualfc/atk/tk/checkbox.go

@@ -0,0 +1,182 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import "fmt"
+
+// check button
+type CheckButton struct {
+	BaseWidget
+	command *Command
+}
+
+func NewCheckButton(parent Widget, text string, attributes ...*WidgetAttr) *CheckButton {
+	theme := checkInitUseTheme(attributes)
+	iid := makeNamedWidgetId(parent, "atk_checkbutton")
+	attributes = append(attributes, &WidgetAttr{"text", text})
+	attributes = append(attributes, &WidgetAttr{"variable", variableId(iid)})
+	info := CreateWidgetInfo(iid, WidgetTypeCheckButton, theme, attributes)
+	if info == nil {
+		return nil
+	}
+	w := &CheckButton{}
+	w.id = iid
+	w.info = info
+	evalSetValue(variableId(iid), "")
+	RegisterWidget(w)
+	return w
+}
+
+func (w *CheckButton) Attach(id string) error {
+	info, err := CheckWidgetInfo(id, WidgetTypeCheckButton)
+	if err != nil {
+		return err
+	}
+	w.id = id
+	w.info = info
+	RegisterWidget(w)
+	return nil
+}
+
+func (w *CheckButton) SetText(text string) error {
+	setObjText("atk_tmp_text", text)
+	return eval(fmt.Sprintf("%v configure -text $atk_tmp_text", w.id))
+}
+
+func (w *CheckButton) Text() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -text", w.id))
+	return r
+}
+
+func (w *CheckButton) SetWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -width {%v}", w.id, width))
+}
+
+func (w *CheckButton) Width() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -width", w.id))
+	return r
+}
+
+func (w *CheckButton) SetImage(image *Image) error {
+	if image == nil {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("%v configure -image {%v}", w.id, image.Id()))
+}
+
+func (w *CheckButton) Image() *Image {
+	r, err := evalAsString(fmt.Sprintf("%v cget -image", w.id))
+	return parserImageResult(r, err)
+}
+
+func (w *CheckButton) SetCompound(compound Compound) error {
+	return eval(fmt.Sprintf("%v configure -compound {%v}", w.id, compound))
+}
+
+func (w *CheckButton) Compound() Compound {
+	r, err := evalAsString(fmt.Sprintf("%v cget -compound", w.id))
+	return parserCompoundResult(r, err)
+}
+
+func (w *CheckButton) SetPaddingN(padx int, pady int) error {
+	if w.info.IsTtk {
+		return eval(fmt.Sprintf("%v configure -padding {%v %v}", w.id, padx, pady))
+	}
+	return eval(fmt.Sprintf("%v configure -padx {%v} -pady {%v}", w.id, padx, pady))
+}
+
+func (w *CheckButton) PaddingN() (int, int) {
+	var r string
+	var err error
+	if w.info.IsTtk {
+		r, err = evalAsString(fmt.Sprintf("%v cget -padding", w.id))
+	} else {
+		r1, _ := evalAsString(fmt.Sprintf("%v cget -padx", w.id))
+		r2, _ := evalAsString(fmt.Sprintf("%v cget -pady", w.id))
+		r = r1 + " " + r2
+	}
+	return parserPaddingResult(r, err)
+}
+
+func (w *CheckButton) SetPadding(pad Pad) error {
+	return w.SetPaddingN(pad.X, pad.Y)
+}
+
+func (w *CheckButton) Padding() Pad {
+	x, y := w.PaddingN()
+	return Pad{x, y}
+}
+
+func (w *CheckButton) SetState(state State) error {
+	return eval(fmt.Sprintf("%v configure -state {%v}", w.id, state))
+}
+
+func (w *CheckButton) State() State {
+	r, err := evalAsString(fmt.Sprintf("%v cget -state", w.id))
+	return parserStateResult(r, err)
+}
+
+func (w *CheckButton) SetTakeFocus(takefocus bool) error {
+	return eval(fmt.Sprintf("%v configure -takefocus {%v}", w.id, boolToInt(takefocus)))
+}
+
+func (w *CheckButton) IsTakeFocus() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -takefocus", w.id))
+	return r
+}
+
+func (w *CheckButton) SetChecked(check bool) error {
+	return eval(fmt.Sprintf("set %v {%v}", variableId(w.id), boolToInt(check)))
+}
+
+func (w *CheckButton) IsChecked() bool {
+	r, _ := evalAsBool(fmt.Sprintf("set %v", variableId(w.id)))
+	return r
+}
+
+func (w *CheckButton) OnCommand(fn func()) error {
+	if fn == nil {
+		return ErrInvalid
+	}
+	if w.command == nil {
+		w.command = &Command{}
+		bindCommand(w.id, "command", w.command.Invoke)
+	}
+	w.command.Bind(fn)
+	return nil
+}
+
+func (w *CheckButton) Invoke() {
+	eval(fmt.Sprintf("%v invoke", w.id))
+}
+
+func CheckButtonAttrText(text string) *WidgetAttr {
+	return &WidgetAttr{"text", text}
+}
+
+func CheckButtonAttrWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"width", width}
+}
+
+func CheckButtonAttrImage(image *Image) *WidgetAttr {
+	if image == nil {
+		return nil
+	}
+	return &WidgetAttr{"image", image.Id()}
+}
+
+func CheckButtonAttrCompound(compound Compound) *WidgetAttr {
+	return &WidgetAttr{"compound", compound}
+}
+
+func CheckButtonAttrPadding(padding Pad) *WidgetAttr {
+	return &WidgetAttr{"padding", padding}
+}
+
+func CheckButtonAttrState(state State) *WidgetAttr {
+	return &WidgetAttr{"state", state}
+}
+
+func CheckButtonAttrTakeFocus(takefocus bool) *WidgetAttr {
+	return &WidgetAttr{"takefocus", boolToInt(takefocus)}
+}

+ 20 - 0
vendor/github.com/visualfc/atk/tk/clipboard.go

@@ -0,0 +1,20 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import "fmt"
+
+func ClearClipboard() error {
+	return eval("clipboard clear")
+}
+
+func AppendToClipboard(text string) error {
+	pname := "atk_tmp_clip"
+	setObjText(pname, text)
+	return eval(fmt.Sprintf("clipboard append $%v", pname))
+}
+
+func GetClipboardText() string {
+	text, _ := evalAsString("clipboard get -type UTF8_STRING")
+	return text
+}

+ 222 - 0
vendor/github.com/visualfc/atk/tk/combobox.go

@@ -0,0 +1,222 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import "fmt"
+
+// combbox
+type ComboBox struct {
+	BaseWidget
+}
+
+func NewComboBox(parent Widget, attributes ...*WidgetAttr) *ComboBox {
+	theme := checkInitUseTheme(attributes)
+	iid := makeNamedWidgetId(parent, "atk_combobox")
+	attributes = append(attributes, &WidgetAttr{"textvariable", variableId(iid)})
+	info := CreateWidgetInfo(iid, WidgetTypeComboBox, theme, attributes)
+	if info == nil {
+		return nil
+	}
+	w := &ComboBox{}
+	w.id = iid
+	w.info = info
+	evalSetValue(variableId(iid), "")
+	RegisterWidget(w)
+	return w
+}
+
+func (w *ComboBox) Attach(id string) error {
+	info, err := CheckWidgetInfo(id, WidgetTypeComboBox)
+	if err != nil {
+		return err
+	}
+	w.id = id
+	w.info = info
+	RegisterWidget(w)
+	return nil
+}
+
+func (w *ComboBox) SetFont(font Font) error {
+	if font == nil {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("%v configure -font {%v}", w.id, font.Id()))
+}
+
+func (w *ComboBox) Font() Font {
+	r, err := evalAsString(fmt.Sprintf("%v cget -font", w.id))
+	return parserFontResult(r, err)
+}
+
+func (w *ComboBox) SetBackground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -background $atk_tmp_text", w.id))
+}
+
+func (w *ComboBox) Background() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -background", w.id))
+	return r
+}
+
+func (w *ComboBox) SetForground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -foreground $atk_tmp_text", w.id))
+}
+
+func (w *ComboBox) Forground() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -foreground", w.id))
+	return r
+}
+
+func (w *ComboBox) SetJustify(justify Justify) error {
+	return eval(fmt.Sprintf("%v configure -justify {%v}", w.id, justify))
+}
+
+func (w *ComboBox) Justify() Justify {
+	r, err := evalAsString(fmt.Sprintf("%v cget -justify", w.id))
+	return parserJustifyResult(r, err)
+}
+
+func (w *ComboBox) SetWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -width {%v}", w.id, width))
+}
+
+func (w *ComboBox) Width() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -width", w.id))
+	return r
+}
+
+func (w *ComboBox) SetHeight(height int) error {
+	return eval(fmt.Sprintf("%v configure -height {%v}", w.id, height))
+}
+
+func (w *ComboBox) Height() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -height", w.id))
+	return r
+}
+
+func (w *ComboBox) SetEcho(echo string) error {
+	setObjText("atk_tmp_text", echo)
+	return eval(fmt.Sprintf("%v configure -show $atk_tmp_text", w.id))
+}
+
+func (w *ComboBox) Echo() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -show", w.id))
+	return r
+}
+
+func (w *ComboBox) SetState(state State) error {
+	return eval(fmt.Sprintf("%v configure -state {%v}", w.id, state))
+}
+
+func (w *ComboBox) State() State {
+	r, err := evalAsString(fmt.Sprintf("%v cget -state", w.id))
+	return parserStateResult(r, err)
+}
+
+func (w *ComboBox) SetTakeFocus(takefocus bool) error {
+	return eval(fmt.Sprintf("%v configure -takefocus {%v}", w.id, boolToInt(takefocus)))
+}
+
+func (w *ComboBox) IsTakeFocus() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -takefocus", w.id))
+	return r
+}
+
+func (w *ComboBox) SetValues(values []string) error {
+	setObjTextList("atk_tmp_textlist", values)
+	return eval(fmt.Sprintf("%v configure -values $atk_tmp_textlist", w.id))
+}
+
+func (w *ComboBox) Values() []string {
+	r, _ := evalAsStringList(fmt.Sprintf("%v cget -values", w.id))
+	return r
+}
+
+func (w *ComboBox) OnSelected(fn func()) error {
+	if fn == nil {
+		return ErrInvalid
+	}
+	w.BindEvent("<<ComboboxSelected>>", func(e *Event) {
+		fn()
+	})
+	return nil
+}
+
+func (w *ComboBox) OnEditReturn(fn func()) error {
+	if fn == nil {
+		return ErrInvalid
+	}
+	w.BindEvent("<Return>", func(e *Event) {
+		fn()
+	})
+	return nil
+}
+
+func (w *ComboBox) Entry() *Entry {
+	return &Entry{w.BaseWidget, nil}
+}
+
+func (w *ComboBox) SetCurrentText(text string) *ComboBox {
+	setObjText("atk_tmp_text", text)
+	eval(fmt.Sprintf("%v set $atk_tmp_text", w.id))
+	return w
+}
+
+func (w *ComboBox) CurrentText() string {
+	r, _ := evalAsString(fmt.Sprintf("%v get", w.id))
+	return r
+}
+
+func (w *ComboBox) SetCurrentIndex(index int) *ComboBox {
+	eval(fmt.Sprintf("%v current {%v}", w.id, index))
+	return w
+}
+
+func (w *ComboBox) CurrentIndex() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v current", w.id))
+	return r
+}
+
+func ComboBoxAttrFont(font Font) *WidgetAttr {
+	if font == nil {
+		return nil
+	}
+	return &WidgetAttr{"font", font.Id()}
+}
+
+func ComboBoxAttrBackground(color string) *WidgetAttr {
+	return &WidgetAttr{"background", color}
+}
+
+func ComboBoxAttrForground(color string) *WidgetAttr {
+	return &WidgetAttr{"foreground", color}
+}
+
+func ComboBoxAttrJustify(justify Justify) *WidgetAttr {
+	return &WidgetAttr{"justify", justify}
+}
+
+func ComboBoxAttrWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"width", width}
+}
+
+func ComboBoxAttrHeight(height int) *WidgetAttr {
+	return &WidgetAttr{"height", height}
+}
+
+func ComboBoxAttrEcho(echo string) *WidgetAttr {
+	return &WidgetAttr{"show", echo}
+}
+
+func ComboBoxAttrState(state State) *WidgetAttr {
+	return &WidgetAttr{"state", state}
+}
+
+func ComboBoxAttrTakeFocus(takefocus bool) *WidgetAttr {
+	return &WidgetAttr{"takefocus", boolToInt(takefocus)}
+}
+
+func ComboBoxAttrValues(values []string) *WidgetAttr {
+	return &WidgetAttr{"values", values}
+}

+ 92 - 0
vendor/github.com/visualfc/atk/tk/command.go

@@ -0,0 +1,92 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+	"sync"
+)
+
+type Command struct {
+	sync.RWMutex
+	cmds []func()
+}
+
+func (c *Command) Bind(fn func()) {
+	if fn == nil {
+		return
+	}
+	c.Lock()
+	c.cmds = append(c.cmds, fn)
+	c.Unlock()
+}
+
+func (c *Command) Clear() {
+	c.Lock()
+	c.cmds = nil
+	c.Unlock()
+}
+
+func (c *Command) Invoke() {
+	c.RLock()
+	for _, cmd := range c.cmds {
+		if cmd != nil {
+			cmd()
+		}
+	}
+	c.RUnlock()
+}
+
+type CommandEx struct {
+	sync.RWMutex
+	cmds []func([]string) error
+}
+
+func (c *CommandEx) Bind(fn func([]string) error) {
+	if fn == nil {
+		return
+	}
+	c.Lock()
+	c.cmds = append(c.cmds, fn)
+	c.Unlock()
+}
+
+func (c *CommandEx) Clear() {
+	c.Lock()
+	c.cmds = nil
+	c.Unlock()
+}
+
+func (c *CommandEx) Invoke(args []string) {
+	c.RLock()
+	for _, cmd := range c.cmds {
+		if cmd != nil {
+			cmd(args)
+		}
+	}
+	c.RUnlock()
+}
+
+func bindCommand(id string, command string, fn func()) error {
+	actName := makeActionId()
+	err := eval(fmt.Sprintf("%v configure -%v {%v}", id, command, actName))
+	if err != nil {
+		return err
+	}
+	mainInterp.CreateAction(actName, func(args []string) {
+		fn()
+	})
+	return nil
+}
+
+func bindCommandEx(id string, command string, fn func([]string)) error {
+	actName := makeActionId()
+	err := eval(fmt.Sprintf("%v configure -%v {%v}", id, command, actName))
+	if err != nil {
+		return err
+	}
+	mainInterp.CreateAction(actName, func(args []string) {
+		fn(args)
+	})
+	return nil
+}

+ 222 - 0
vendor/github.com/visualfc/atk/tk/dialog.go

@@ -0,0 +1,222 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+)
+
+//tk_chooseColor — pops up a dialog box for the user to select a color.
+func ChooseColor(parent Widget, title string, initcolor string) (string, error) {
+	script := fmt.Sprintf("tk_chooseColor")
+	if parent != nil {
+		script += " -parent " + parent.Id()
+	}
+	if initcolor != "" {
+		script += " -initialcolor " + initcolor
+	}
+	if title != "" {
+		setObjText("atk_tmp_title", title)
+		script += " -title $atk_tmp_title"
+	}
+	return evalAsString(script)
+}
+
+//tk_chooseDirectory — pops up a dialog box for the user to select a directory.
+func ChooseDirectory(parent Widget, title string, initialdir string, mustexist bool) (string, error) {
+	script := fmt.Sprintf("tk_chooseDirectory")
+	if parent != nil {
+		script += " -parent " + parent.Id()
+	}
+	if initialdir != "" {
+		setObjText("atk_tmp_initialdir", initialdir)
+		script += " -initialdir $atk_tmp_initialdir"
+	}
+	if mustexist {
+		script += " -mustexist true"
+	}
+	if title != "" {
+		setObjText("atk_tmp_title", title)
+		script += " -title $atk_tmp_title"
+	}
+	return evalAsString(script)
+}
+
+type FileType struct {
+	Info string
+	Ext  string
+}
+
+func (v FileType) String() string {
+	return fmt.Sprintf("{%v} {%v}", v.Info, v.Ext)
+}
+
+//tk_getOpenFile, tk_getSaveFile — pop up a dialog box for the user to select a file to open or save.
+func GetOpenFile(parent Widget, title string, filetypes []FileType, initialdir string, initialfile string) (string, error) {
+	script := fmt.Sprintf("tk_getOpenFile")
+	if parent != nil {
+		script += " -parent " + parent.Id()
+	}
+	if filetypes != nil {
+		var info []string
+		for _, v := range filetypes {
+			info = append(info, v.String())
+		}
+		setObjTextList("atk_tmp_filetypes", info)
+		script += " -filetypes $atk_tmp_filetypes"
+	}
+	if initialdir != "" {
+		setObjText("atk_tmp_initialdir", initialdir)
+		script += " -initialdir $atk_tmp_initialdir"
+	}
+	if initialfile != "" {
+		setObjText("atk_tmp_initialfile", initialfile)
+		script += " -initialfile $atk_tmp_initialfile"
+	}
+	if title != "" {
+		setObjText("atk_tmp_title", title)
+		script += " -title $atk_tmp_title"
+	}
+	return evalAsString(script)
+}
+
+func GetOpenMultipleFile(parent Widget, title string, filetypes []FileType, initialdir string, initialfile string) ([]string, error) {
+	script := fmt.Sprintf("tk_getOpenFile")
+	if parent != nil {
+		script += " -parent " + parent.Id()
+	}
+	if filetypes != nil {
+		var info []string
+		for _, v := range filetypes {
+			info = append(info, v.String())
+		}
+		setObjTextList("atk_tmp_filetypes", info)
+		script += " -filetypes $atk_tmp_filetypes"
+	}
+	if initialdir != "" {
+		setObjText("atk_tmp_initialdir", initialdir)
+		script += " -initialdir $atk_tmp_initialdir"
+	}
+	if initialfile != "" {
+		setObjText("atk_tmp_initialfile", initialfile)
+		script += " -initialfile $atk_tmp_initialfile"
+	}
+	if title != "" {
+		setObjText("atk_tmp_title", title)
+		script += " -title $atk_tmp_title"
+	}
+	script += " -multiple true"
+	return evalAsStringList(script)
+}
+
+//tk_getOpenFile, tk_getSaveFile — pop up a dialog box for the user to select a file to open or save.
+func GetSaveFile(parent Widget, title string, confirmoverwrite bool, defaultextension string, filetypes []FileType, initialdir string, initialfile string) (string, error) {
+	script := fmt.Sprintf("tk_getSaveFile")
+	if parent != nil {
+		script += " -parent " + parent.Id()
+	}
+	if mainInterp.SupportTk86() {
+		script += " -confirmoverwrite " + fmt.Sprint(confirmoverwrite)
+	}
+	if defaultextension != "" {
+		setObjText("atk_tmp_defaultextension", defaultextension)
+		script += " -defaultextension $atk_tmp_defaultextension"
+	}
+	if filetypes != nil {
+		var info []string
+		for _, v := range filetypes {
+			info = append(info, v.String())
+		}
+		setObjTextList("atk_tmp_filetypes", info)
+		script += " -filetypes $atk_tmp_filetypes"
+	}
+	if initialdir != "" {
+		setObjText("atk_tmp_initialdir", initialdir)
+		script += " -initialdir $atk_tmp_initialdir"
+	}
+	if initialfile != "" {
+		setObjText("atk_tmp_initialfile", initialfile)
+		script += " -initialfile $atk_tmp_initialfile"
+	}
+	if title != "" {
+		setObjText("atk_tmp_title", title)
+		script += " -title $atk_tmp_title"
+	}
+	return evalAsString(script)
+}
+
+type MessageBoxIcon int
+
+const (
+	MessageBoxIconNone MessageBoxIcon = iota
+	MessageBoxIconError
+	MessageBoxIconInfo
+	MessageBoxIconQuestion
+	MessageBoxIconWarning
+)
+
+var (
+	messageBoxIconName = []string{"", "error", "info", "question", "warning"}
+)
+
+func (v MessageBoxIcon) String() string {
+	if v >= 0 && int(v) < len(messageBoxIconName) {
+		return messageBoxIconName[v]
+	}
+	return ""
+}
+
+type MessageBoxType int
+
+const (
+	MessageBoxTypeOk MessageBoxType = iota
+	MessageBoxTypeOkCancel
+	MessageBoxTypeAbortRetryIgnore
+	MessageBoxTypeRetryCancel
+	MessageBoxTypeYesNo
+	MessageBoxTypeYesNoCancel
+)
+
+var (
+	messageBoxTypeName = []string{"ok", "okcancel", "abortretryignore", "retrycancel", "yesno", "yesnocancel"}
+)
+
+func (v MessageBoxType) String() string {
+	if v >= 0 && int(v) < len(messageBoxTypeName) {
+		return messageBoxTypeName[v]
+	}
+	return ""
+}
+
+//tk_messageBox — pops up a message window and waits for user response.
+func MessageBox(parent Widget, title string, message string, detail string, defaultbutton string, icon MessageBoxIcon, typ MessageBoxType) (string, error) {
+	script := fmt.Sprintf("tk_messageBox")
+	if parent != nil {
+		script += " -parent " + parent.Id()
+	}
+	if defaultbutton != "" {
+		setObjText("atk_tmp_defaultbutton", defaultbutton)
+		script += " -default $atk_tmp_defaultbutton"
+	}
+	if message != "" {
+		setObjText("atk_tmp_message", message)
+		script += " -message $atk_tmp_message"
+	}
+	sicon := icon.String()
+	if sicon != "" {
+		script += " -icon " + sicon
+	}
+	styp := typ.String()
+	if styp != "" {
+		script += " -type " + styp
+	}
+	if detail != "" {
+		setObjText("atk_tmp_detail", detail)
+		script += " -detail $atk_tmp_detail"
+	}
+	if title != "" {
+		setObjText("atk_tmp_title", title)
+		script += " -title $atk_tmp_title"
+	}
+	return evalAsString(script)
+}

+ 311 - 0
vendor/github.com/visualfc/atk/tk/entry.go

@@ -0,0 +1,311 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+	"strings"
+)
+
+// entry
+type Entry struct {
+	BaseWidget
+	xscrollcommand *CommandEx
+}
+
+func NewEntry(parent Widget, attributes ...*WidgetAttr) *Entry {
+	theme := checkInitUseTheme(attributes)
+	iid := makeNamedWidgetId(parent, "atk_entry")
+	attributes = append(attributes, &WidgetAttr{"textvariable", variableId(iid)})
+	info := CreateWidgetInfo(iid, WidgetTypeEntry, theme, attributes)
+	if info == nil {
+		return nil
+	}
+	w := &Entry{}
+	w.id = iid
+	w.info = info
+	evalSetValue(variableId(iid), "")
+	RegisterWidget(w)
+	return w
+}
+
+func (w *Entry) Attach(id string) error {
+	info, err := CheckWidgetInfo(id, WidgetTypeEntry)
+	if err != nil {
+		return err
+	}
+	w.id = id
+	w.info = info
+	RegisterWidget(w)
+	return nil
+}
+
+func (w *Entry) SetForeground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -foreground $atk_tmp_text", w.id))
+}
+
+func (w *Entry) Foreground() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -foreground", w.id))
+	return r
+}
+
+func (w *Entry) SetBackground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -background $atk_tmp_text", w.id))
+}
+
+func (w *Entry) Background() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -background", w.id))
+	return r
+}
+
+func (w *Entry) SetWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -width {%v}", w.id, width))
+}
+
+func (w *Entry) Width() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -width", w.id))
+	return r
+}
+
+func (w *Entry) SetFont(font Font) error {
+	if font == nil {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("%v configure -font {%v}", w.id, font.Id()))
+}
+
+func (w *Entry) Font() Font {
+	r, err := evalAsString(fmt.Sprintf("%v cget -font", w.id))
+	return parserFontResult(r, err)
+}
+
+func (w *Entry) SetJustify(justify Justify) error {
+	return eval(fmt.Sprintf("%v configure -justify {%v}", w.id, justify))
+}
+
+func (w *Entry) Justify() Justify {
+	r, err := evalAsString(fmt.Sprintf("%v cget -justify", w.id))
+	return parserJustifyResult(r, err)
+}
+
+func (w *Entry) SetShow(show string) error {
+	setObjText("atk_tmp_text", show)
+	return eval(fmt.Sprintf("%v configure -show $atk_tmp_text", w.id))
+}
+
+func (w *Entry) Show() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -show", w.id))
+	return r
+}
+
+func (w *Entry) SetState(state State) error {
+	return eval(fmt.Sprintf("%v configure -state {%v}", w.id, state))
+}
+
+func (w *Entry) State() State {
+	r, err := evalAsString(fmt.Sprintf("%v cget -state", w.id))
+	return parserStateResult(r, err)
+}
+
+func (w *Entry) SetTakeFocus(takefocus bool) error {
+	return eval(fmt.Sprintf("%v configure -takefocus {%v}", w.id, boolToInt(takefocus)))
+}
+
+func (w *Entry) IsTakeFocus() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -takefocus", w.id))
+	return r
+}
+
+func (w *Entry) SetExportSelection(export bool) error {
+	return eval(fmt.Sprintf("%v configure -exportselection {%v}", w.id, boolToInt(export)))
+}
+
+func (w *Entry) IsExportSelection() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -exportselection", w.id))
+	return r
+}
+
+func (w *Entry) SetText(text string) error {
+	setObjText("atk_tmp_text", text)
+	return eval(fmt.Sprintf("set %v $atk_tmp_text", variableId(w.id)))
+}
+
+func (w *Entry) Text() string {
+	r, _ := evalAsString(fmt.Sprintf("set %v", variableId(w.id)))
+	return r
+}
+
+func (w *Entry) SetXViewArgs(args []string) error {
+	return eval(fmt.Sprintf("%v xview %v", w.id, strings.Join(args, " ")))
+}
+
+func (w *Entry) OnXScrollEx(fn func([]string) error) error {
+	if fn == nil {
+		return ErrInvalid
+	}
+	if w.xscrollcommand == nil {
+		w.xscrollcommand = &CommandEx{}
+		bindCommandEx(w.id, "xscrollcommand", w.xscrollcommand.Invoke)
+	}
+	w.xscrollcommand.Bind(fn)
+	return nil
+}
+
+func (w *Entry) BindXScrollBar(bar *ScrollBar) error {
+	if !IsValidWidget(bar) {
+		return ErrInvalid
+	}
+	w.OnXScrollEx(bar.SetScrollArgs)
+	bar.OnCommandEx(w.SetXViewArgs)
+	return nil
+}
+
+func (w *Entry) SetCursorPosition(pos int) *Entry {
+	eval(fmt.Sprintf("%v icursor %v", w.id, pos))
+	return w
+}
+
+func (w *Entry) CursorPosition() int {
+	return w.index("insert")
+}
+
+func (w *Entry) OnUpdate(fn func()) error {
+	return traceVariable(variableId(w.id), fn)
+}
+
+func (w *Entry) OnEditReturn(fn func()) error {
+	if fn == nil {
+		return ErrInvalid
+	}
+	w.BindEvent("<Return>", func(e *Event) {
+		fn()
+	})
+	return nil
+}
+
+func (w *Entry) Copy() {
+	SendEvent(w, "<<Copy>>")
+}
+
+func (w *Entry) Paste() {
+	SendEvent(w, "<<Paste")
+}
+
+func (w *Entry) Cut() {
+	SendEvent(w, "<<Cut>>")
+}
+
+func (w *Entry) Clear() {
+	w.SetText("")
+}
+
+func (w *Entry) Delete(index int) {
+	eval(fmt.Sprintf("%v delete %v", w.id, index))
+}
+
+func (w *Entry) DeleteRange(start int, end int) {
+	eval(fmt.Sprintf("%v delete %v %v", w.id, start, end))
+}
+
+func (w *Entry) TextLength() int {
+	return w.index("end")
+}
+
+func (w *Entry) index(index string) int {
+	r, _ := evalAsInt(fmt.Sprintf("%v index %v", w.id, index))
+	return r
+}
+
+func (w *Entry) Index(index int) int {
+	r, _ := evalAsInt(fmt.Sprintf("%v index %v", w.id, index))
+	return r
+}
+
+func (w *Entry) Insert(index int, str string) error {
+	setObjText("atk_entry_text", str)
+	return eval(fmt.Sprintf("%v insert %v $atk_entry_text", w.id, index))
+}
+
+func (w *Entry) Append(str string) error {
+	setObjText("atk_entry_text", str)
+	return eval(fmt.Sprintf("%v insert end $atk_entry_text", w.id))
+}
+
+func (w *Entry) ClearSelection() {
+	eval(fmt.Sprintf("%v selection clear", w.id))
+}
+
+func (w *Entry) HasSelectedText() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v selection present", w.id))
+	return r
+}
+
+func (w *Entry) SelectedText() string {
+	if !w.HasSelectedText() {
+		return ""
+	}
+	return SubString(w.Text(), w.SelectionStart(), w.SelectionEnd())
+}
+
+func (w *Entry) SetSelection(start int, end int) {
+	eval(fmt.Sprintf("%v selection range %v %v", w.id, start, end))
+}
+
+func (w *Entry) SelectAll() {
+	w.SetSelection(0, w.TextLength())
+}
+
+func (w *Entry) SelectionStart() int {
+	if !w.HasSelectedText() {
+		return -1
+	}
+	return w.index("sel.first")
+}
+
+func (w *Entry) SelectionEnd() int {
+	if !w.HasSelectedText() {
+		return -1
+	}
+	return w.index("sel.last")
+}
+
+func EntryAttrForeground(color string) *WidgetAttr {
+	return &WidgetAttr{"foreground", color}
+}
+
+func EntryAttrBackground(color string) *WidgetAttr {
+	return &WidgetAttr{"background", color}
+}
+
+func EntryAttrWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"width", width}
+}
+
+func EntryAttrFont(font Font) *WidgetAttr {
+	if font == nil {
+		return nil
+	}
+	return &WidgetAttr{"font", font.Id()}
+}
+
+func EntryAttrJustify(justify Justify) *WidgetAttr {
+	return &WidgetAttr{"justify", justify}
+}
+
+func EntryAttrShow(show string) *WidgetAttr {
+	return &WidgetAttr{"show", show}
+}
+
+func EntryAttrState(state State) *WidgetAttr {
+	return &WidgetAttr{"state", state}
+}
+
+func EntryAttrTakeFocus(takefocus bool) *WidgetAttr {
+	return &WidgetAttr{"takefocus", boolToInt(takefocus)}
+}
+
+func EntryAttrExportSelection(export bool) *WidgetAttr {
+	return &WidgetAttr{"exportselection", boolToInt(export)}
+}

+ 13 - 0
vendor/github.com/visualfc/atk/tk/error.go

@@ -0,0 +1,13 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import "errors"
+
+var (
+	ErrInvalid   = errors.New("invalid argument")
+	ErrExist     = errors.New("already exists")
+	ErrNotExist  = errors.New("does not exist")
+	ErrClosed    = errors.New("already closed")
+	ErrUnsupport = errors.New("unsupport")
+)

+ 351 - 0
vendor/github.com/visualfc/atk/tk/event.go

@@ -0,0 +1,351 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+	"unicode/utf8"
+)
+
+type Event struct {
+	//The type field from the event. Valid for all event types.
+	Type int
+
+	//The send_event field from the event. Valid for all event types.
+	//0 indicates that this is a “normal” event, 1 indicates that it is a “synthetic” event generated by SendEvent.
+	Synthetic bool
+
+	//The path name of the window to which the event was reported (the window field from the event). Valid for all event types.
+	Widget Widget
+
+	//The time field from the event. This is the X server timestamp (typically the time since the last server reset) in milliseconds,
+	//when the event occurred. Valid for most events.
+	Timestamp int64
+
+	//The number of the button that was pressed or released.
+	//Valid only for ButtonPress and ButtonRelease events.
+	MouseButton int
+
+	//The x and y fields from the event. For ButtonPress, ButtonRelease, Motion, KeyPress, KeyRelease, and MouseWheel events,
+	//%x and %y indicate the position of the mouse pointer relative to the receiving window.
+	//For Enter and Leave events, the position where the mouse pointer crossed the window, relative to the receiving window.
+	//For Configure and Create requests, the x and y coordinates of the window relative to its parent window.
+	PosX int
+	PosY int
+
+	GlobalPosX int
+	GlobalPosY int
+
+	//This reports the delta value of a MouseWheel event.
+	//The delta value represents the rotation units the mouse wheel has been moved.
+	//The sign of the value represents the direction the mouse wheel was scrolled.
+	WheelDelta int
+
+	//The keycode field from the event. Valid only for KeyPress and KeyRelease events.
+	KeyCode int
+	KeySym  string
+	KeyText string
+	KeyRune rune
+
+	//The detail or user_data field from the event. The %d is replaced by a string identifying the detail.
+	//For Enter, Leave, FocusIn, and FocusOut events, the string will be one of the following:
+	//NotifyAncestor NotifyNonlinearVirtual NotifyDetailNone
+	//NotifyPointer NotifyInferior NotifyPointerRoot NotifyNonlinear NotifyVirtual
+	//For ConfigureRequest events, the string will be one of:
+	//Above Opposite Below None BottomIf TopIf
+	//For virtual events, the string will be whatever value is stored in the user_data field when the event was created (typically with event generate),
+	//or the empty string if the field is NULL. Virtual events corresponding to key sequence presses (see event add for details) set the user_data to NULL.
+	//For events other than these, the substituted string is undefined.
+	UserData string
+
+	//The focus field from the event (0 or 1). Valid only for Enter and Leave events.
+	//1 if the receiving window is the focus window or a descendant of the focus window, 0 otherwise.
+	Focus bool
+
+	//The width/height field from the event. Valid for the Configure, ConfigureRequest, Create, ResizeRequest, and Expose events.
+	//Indicates the new or requested width/height of the window.
+	Width  int
+	Height int
+
+	//The mode field from the event. The substituted string is one of NotifyNormal, NotifyGrab, NotifyUngrab, or NotifyWhileGrabbed.
+	//Valid only for Enter, FocusIn, FocusOut, and Leave events.
+	Mode string
+
+	//The override_redirect field from the event. Valid only for Map, Reparent, and Configure events.
+	OverrideRedirect string
+
+	//The place field from the event, substituted as one of the strings PlaceOnTop or PlaceOnBottom.
+	//Valid only for Circulate and CirculateRequest events.
+	Place string
+
+	//The state field from the event. For ButtonPress, ButtonRelease, Enter, KeyPress, KeyRelease, Leave, and Motion events,
+	//a decimal string is substituted. For Visibility, one of the strings VisibilityUnobscured, VisibilityPartiallyObscured, and VisibilityFullyObscured is substituted.
+	//For Property events, substituted with either the string NewValue (indicating that the property has been created or modified) or Delete (indicating that the property has been removed).
+	State string
+}
+
+func (e *Event) params() string {
+	return "%T %E %W %t %b %x %y %D %k %K %A %d %f %w %h %m %o %p %s %X %Y"
+}
+
+func (e *Event) parser(args []string) {
+	e.Type = e.toInt(args[0])
+	e.Synthetic = e.toBool(args[1])
+	e.Widget = FindWidget(args[2])
+	e.Timestamp = e.toInt64(args[3])
+	if e.Timestamp < 0 {
+		e.Timestamp = 0
+	}
+	e.MouseButton = e.toInt(args[4])
+	e.PosX = e.toInt(args[5])
+	e.PosY = e.toInt(args[6])
+	e.WheelDelta = e.toInt(args[7])
+	e.KeyCode = e.toInt(args[8])
+	e.KeySym = e.toString(args[9])
+	e.KeyText = e.toString(args[10])
+	if e.KeyText != "" {
+		e.KeyRune, _ = utf8.DecodeRuneInString(e.KeyText)
+	}
+	e.UserData = e.toString(args[11])
+	e.Focus = e.toBool(args[12])
+	e.Width = e.toInt(args[13])
+	e.Height = e.toInt(args[14])
+	e.Mode = e.toString(args[15])
+	e.OverrideRedirect = e.toString(args[16])
+	e.Place = e.toString(args[17])
+	e.State = e.toString(args[18])
+	e.GlobalPosX = e.toInt(args[19])
+	e.GlobalPosY = e.toInt(args[20])
+}
+
+func (e *Event) toInt(s string) int {
+	v, _ := strconv.ParseInt(s, 10, 0)
+	return int(v)
+}
+
+func (e *Event) toInt64(s string) int64 {
+	v, _ := strconv.ParseInt(s, 10, 0)
+	return v
+}
+
+func (e *Event) toBool(s string) bool {
+	if s == "1" {
+		return true
+	}
+	return false
+}
+
+func (e *Event) toString(s string) string {
+	if s == "??" {
+		return ""
+	}
+	return s
+}
+
+type KeyModifier int
+
+const (
+	KeyModifierNone KeyModifier = 1 << iota
+	KeyModifierShift
+	KeyModifierControl
+	KeyModifierAlt
+	KeyModifierMeta
+	KeyModifierFn
+)
+
+func (k KeyModifier) String() string {
+	var ar []string
+	if k&KeyModifierShift == KeyModifierShift {
+		ar = append(ar, "Shift")
+	}
+	if k&KeyModifierControl == KeyModifierControl {
+		ar = append(ar, "Control")
+	}
+	if k&KeyModifierAlt == KeyModifierAlt {
+		ar = append(ar, "Alt")
+	}
+	if k&KeyModifierMeta == KeyModifierMeta {
+		ar = append(ar, "Meta")
+	}
+	return strings.Join(ar, " ")
+}
+
+type KeyEvent struct {
+	*Event
+	KeyModifier KeyModifier
+}
+
+func (e *KeyEvent) addModifier(sym string, name string, mod KeyModifier) {
+	if strings.HasPrefix(sym, name) {
+		e.KeyModifier |= mod
+	}
+}
+
+func (e *KeyEvent) removeModifier(sym string, name string, mod KeyModifier) {
+	if strings.HasPrefix(sym, name) {
+		if e.KeyModifier&mod == mod {
+			e.KeyModifier ^= mod
+		}
+	}
+}
+
+//TODO: almost check key modifier
+func BindKeyEventEx(tag string, fnPress func(e *KeyEvent), fnRelease func(e *KeyEvent)) error {
+	var ke KeyEvent
+	var err error
+	err = BindEvent(tag, "<KeyPress>", func(e *Event) {
+		ke.addModifier(e.KeySym, "Shift_", KeyModifierShift)
+		ke.addModifier(e.KeySym, "Control_", KeyModifierControl)
+		ke.addModifier(e.KeySym, "Alt_", KeyModifierAlt)
+		ke.addModifier(e.KeySym, "Meta_", KeyModifierMeta)
+		ke.addModifier(e.KeySym, "Super_", KeyModifierFn)
+		ke.Event = e
+		if fnPress != nil {
+			fnPress(&ke)
+		}
+	})
+	if err != nil {
+		return err
+	}
+	err = BindEvent(tag, "<KeyRelease>", func(e *Event) {
+		ke.Event = e
+		if fnRelease != nil {
+			fnRelease(&ke)
+		}
+		ke.removeModifier(e.KeySym, "Shift_", KeyModifierShift)
+		ke.removeModifier(e.KeySym, "Control_", KeyModifierControl)
+		ke.removeModifier(e.KeySym, "Alt_", KeyModifierAlt)
+		ke.removeModifier(e.KeySym, "Meta_", KeyModifierMeta)
+		ke.removeModifier(e.KeySym, "Super_", KeyModifierFn)
+	})
+	return err
+}
+
+func bindEventHelper(tag string, event string, fnid string, ev *Event, fn func()) error {
+	mainInterp.CreateAction(fnid, func(args []string) {
+		ev.parser(args)
+		fn()
+	})
+	return eval(fmt.Sprintf("bind %v %v {%v %v}", tag, event, fnid, ev.params()))
+}
+
+func addEventHelper(tag string, event string, fnid string, ev *Event, fn func()) error {
+	mainInterp.CreateAction(fnid, func(args []string) {
+		ev.parser(args)
+		fn()
+	})
+	return eval(fmt.Sprintf("bind %v %v {+%v %v}", tag, event, fnid, ev.params()))
+}
+
+func IsEvent(event string) bool {
+	return strings.HasPrefix(event, "<") && strings.HasSuffix(event, ">")
+}
+
+func IsVirtualEvent(event string) bool {
+	return strings.HasPrefix(event, "<<") && strings.HasSuffix(event, ">>")
+}
+
+// add bind event
+func BindEvent(tag string, event string, fn func(e *Event)) error {
+	if tag == "" || !IsEvent(event) {
+		return ErrInvalid
+	}
+	fnid := makeBindEventId()
+	var ev Event
+	return addEventHelper(tag, event, fnid, &ev, func() {
+		fn(&ev)
+	})
+}
+
+// clear tag event
+func ClearBindEvent(tag string, event string) error {
+	if tag == "" || !IsEvent(event) {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("bind %v %v {}", tag, event))
+}
+
+func BindInfo(tag string) []string {
+	if tag == "" {
+		return nil
+	}
+	v, _ := evalAsStringList(fmt.Sprintf("bind %v", tag))
+	return v
+}
+
+//Associates the virtual event virtual with the physical event sequence(s)
+//given by the sequence arguments, so that the virtual event will trigger
+//whenever any one of the sequences occurs. Virtual may be any string value
+//and sequence may have any of the values allowed for the sequence argument
+// to the bind command. If virtual is already defined, the new physical event
+// sequences add to the existing sequences for the event.
+func AddVirtualEventPhysicalEvent(virtual string, event string, events ...string) error {
+	if !IsVirtualEvent(virtual) {
+		return ErrInvalid
+	}
+	eventList := append([]string{event}, events...)
+	return eval(fmt.Sprintf("event add %v %v", virtual, strings.Join(eventList, " ")))
+}
+
+//Deletes each of the sequences from those associated with the virtual event
+// given by virtual. Virtual may be any string value and sequence may have
+//any of the values allowed for the sequence argument to the bind command.
+//Any sequences not currently associated with virtual are ignored.
+//If no sequence argument is provided, all physical event sequences are removed
+// for virtual, so that the virtual event will not trigger anymore.
+func RemoveVirtualEventPhysicalEvent(virtual string, events ...string) error {
+	if !IsVirtualEvent(virtual) {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("event remove %v %v", virtual, strings.Join(events, " ")))
+}
+
+func VirtualEventInfo(virtual string) []string {
+	if !IsVirtualEvent(virtual) {
+		return nil
+	}
+	r, _ := evalAsStringList(fmt.Sprintf("event info %v", virtual))
+	return r
+}
+
+//TODO: event attr
+type EventAttr struct {
+	key   string
+	value string
+}
+
+func NativeEventAttr(key string, value string) *EventAttr {
+	return &EventAttr{key, value}
+}
+
+func SendEvent(widget Widget, event string, attrs ...*EventAttr) error {
+	if !IsValidWidget(widget) {
+		return ErrInvalid
+	}
+	return sendEvent(widget.Id(), event, attrs...)
+}
+
+func SendEventToFocus(event string, attrs ...*EventAttr) error {
+	return sendEvent("[focus]", event, attrs...)
+}
+
+func sendEvent(id string, event string, attrs ...*EventAttr) error {
+	if !IsEvent(event) {
+		return ErrInvalid
+	}
+	var list []string
+	for _, attr := range attrs {
+		if attr == nil {
+			continue
+		}
+		list = append(list, fmt.Sprintf("-%v {%v}", attr.key, attr.value))
+	}
+	var script string
+	script = fmt.Sprintf("event generate %v %v", id, event)
+	if len(list) > 0 {
+		script += " " + strings.Join(list, " ")
+	}
+	return eval(script)
+}

+ 272 - 0
vendor/github.com/visualfc/atk/tk/font.go

@@ -0,0 +1,272 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+	"strings"
+)
+
+type Font interface {
+	Id() string
+	IsValid() bool
+	String() string
+	Description() string
+	Family() string
+	Size() int
+	IsBold() bool
+	IsItalic() bool
+	IsUnderline() bool
+	IsOverstrike() bool
+}
+
+type FontAttr struct {
+	key   string
+	value interface{}
+}
+
+func FontAttrBold() *FontAttr {
+	return &FontAttr{"weight", "bold"}
+}
+
+func FontAttrItalic() *FontAttr {
+	return &FontAttr{"slant", "italic"}
+}
+
+func FontAttrUnderline() *FontAttr {
+	return &FontAttr{"underline", 1}
+}
+
+func FontAttrOverstrike() *FontAttr {
+	return &FontAttr{"overstrike", 1}
+}
+
+type BaseFont struct {
+	id string
+}
+
+func (f *BaseFont) Id() string {
+	return f.id
+}
+
+func (f *BaseFont) IsValid() bool {
+	return f.id != ""
+}
+
+func (w *BaseFont) String() string {
+	return fmt.Sprintf("Font{%v}", w.id)
+}
+
+func (w *BaseFont) Description() string {
+	if w.id == "" {
+		return ""
+	}
+	r, _ := evalAsString(fmt.Sprintf("font actual %v", w.id))
+	return r
+}
+
+func (w *BaseFont) Family() string {
+	r, _ := evalAsString(fmt.Sprintf("font actual %v -family", w.id))
+	return r
+}
+
+func (w *BaseFont) Size() int {
+	r, _ := evalAsInt(fmt.Sprintf("font actual %v -size", w.id))
+	return r
+}
+
+func (w *BaseFont) IsBold() bool {
+	r, _ := evalAsString(fmt.Sprintf("font actual %v -weight", w.id))
+	return r == "bold"
+}
+
+func (w *BaseFont) IsItalic() bool {
+	r, _ := evalAsString(fmt.Sprintf("font actual %v -slant", w.id))
+	return r == "italic"
+}
+
+func (w *BaseFont) IsUnderline() bool {
+	r, _ := evalAsBool(fmt.Sprintf("font actual %v -underline", w.id))
+	return r
+}
+
+func (w *BaseFont) IsOverstrike() bool {
+	r, _ := evalAsBool(fmt.Sprintf("font actual %v -overstrike", w.id))
+	return r
+}
+
+func (w *BaseFont) MeasureTextWidth(text string) int {
+	setObjText("atk_tmp_text", text)
+	r, _ := evalAsInt(fmt.Sprintf("font measure %v $atk_tmp_text", w.id))
+	return r
+}
+
+func (w *BaseFont) Ascent() int {
+	r, _ := evalAsInt(fmt.Sprintf("font metrics %v -ascent", w.id))
+	return r
+}
+
+func (w *BaseFont) Descent() int {
+	r, _ := evalAsInt(fmt.Sprintf("font metrics %v -descent", w.id))
+	return r
+}
+
+func (w *BaseFont) Clone() *UserFont {
+	iid := makeNamedId("atk_font")
+	script := fmt.Sprintf("font create %v %v", iid, w.Description())
+	if eval(script) != nil {
+		return nil
+	}
+	return &UserFont{BaseFont{iid}}
+}
+
+type UserFont struct {
+	BaseFont
+}
+
+func (f *UserFont) Destroy() error {
+	if f.id == "" {
+		return ErrInvalid
+	}
+	eval(fmt.Sprintf("font delete %v", f.id))
+	f.id = ""
+	return nil
+}
+
+func NewUserFont(family string, size int, attributes ...*FontAttr) *UserFont {
+	var attrList []string
+	for _, attr := range attributes {
+		if attr == nil {
+			continue
+		}
+		attrList = append(attrList, fmt.Sprintf("-%v {%v}", attr.key, attr.value))
+	}
+	iid := makeNamedId("atk_font")
+	setObjText("atk_tmp_family", family)
+	script := fmt.Sprintf("font create %v -family $atk_tmp_family -size %v", iid, size)
+	if len(attrList) > 0 {
+		script += " " + strings.Join(attrList, " ")
+	}
+	err := eval(script)
+	if err != nil {
+		return nil
+	}
+	return &UserFont{BaseFont{iid}}
+}
+
+func NewUserFontFromClone(font Font) *UserFont {
+	if font == nil {
+		return nil
+	}
+	iid := makeNamedId("atk_font")
+	script := fmt.Sprintf("font create %v", iid)
+	if font != nil {
+		script += " " + font.Description()
+	}
+	err := eval(script)
+	if err != nil {
+		return nil
+	}
+	return &UserFont{BaseFont{iid}}
+}
+
+func (w *UserFont) SetFamily(family string) error {
+	setObjText("atk_tmp_family", family)
+	return eval(fmt.Sprintf("font configure %v -family $atk_tmp_family", w.id))
+}
+
+func (w *UserFont) SetSize(size int) error {
+	return eval(fmt.Sprintf("font configure %v -size {%v}", w.id, size))
+}
+
+func (w *UserFont) SetBold(bold bool) error {
+	var v string
+	if bold {
+		v = "bold"
+	} else {
+		v = "normal"
+	}
+	return eval(fmt.Sprintf("font configure %v -weight {%v}", w.id, v))
+}
+
+func (w *UserFont) SetItalic(italic bool) error {
+	var v string
+	if italic {
+		v = "italic"
+	} else {
+		v = "roman"
+	}
+	return eval(fmt.Sprintf("font configure %v -slant {%v}", w.id, v))
+}
+
+func (w *UserFont) SetUnderline(underline bool) error {
+	return eval(fmt.Sprintf("font configure %v -underline {%v}", w.id, boolToInt(underline)))
+}
+
+func (w *UserFont) SetOverstrike(overstrike bool) error {
+	return eval(fmt.Sprintf("font configure %v -overstrike {%v}", w.id, boolToInt(overstrike)))
+}
+
+func FontFamilieList() []string {
+	r, _ := evalAsStringList("font families")
+	return r
+}
+
+//tk system default font
+type SysFont struct {
+	BaseFont
+}
+
+type SysFontType int
+
+const (
+	SysDefaultFont SysFontType = 0
+	SysTextFont
+	SysFixedFont
+	SysMenuFont
+	SysHeadingFont
+	SysCaptionFont
+	SysSmallCaptionFont
+	SysIconFont
+	SysTooltipFont
+)
+
+var (
+	sysFontNameList = []string{
+		"TKDefaultFont",
+		"TKTextFont",
+		"TKFixedFont",
+		"TKMenuFont",
+		"TKHeadingFont",
+		"TKCaptionFont",
+		"TKSmallCaptionFont",
+		"TKIconFont",
+		"TKTooltipFont",
+	}
+	sysFontList []*SysFont
+)
+
+func init() {
+	for _, name := range sysFontNameList {
+		sysFontList = append(sysFontList, &SysFont{BaseFont{name}})
+	}
+}
+
+func LoadSysFont(typ SysFontType) *SysFont {
+	if int(typ) >= 0 && int(typ) < len(sysFontList) {
+		return sysFontList[typ]
+	}
+	return nil
+}
+
+func parserFontResult(r string, err error) Font {
+	if err != nil || r == "" {
+		return nil
+	}
+	for _, f := range sysFontList {
+		if f.Id() == r {
+			return f
+		}
+	}
+	return &UserFont{BaseFont{r}}
+}

+ 133 - 0
vendor/github.com/visualfc/atk/tk/frame.go

@@ -0,0 +1,133 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import "fmt"
+
+// frame
+type Frame struct {
+	BaseWidget
+}
+
+func NewFrame(parent Widget, attributes ...*WidgetAttr) *Frame {
+	theme := checkInitUseTheme(attributes)
+	iid := makeNamedWidgetId(parent, "atk_frame")
+	info := CreateWidgetInfo(iid, WidgetTypeFrame, theme, attributes)
+	if info == nil {
+		return nil
+	}
+	w := &Frame{}
+	w.id = iid
+	w.info = info
+	RegisterWidget(w)
+	return w
+}
+
+func (w *Frame) Attach(id string) error {
+	info, err := CheckWidgetInfo(id, WidgetTypeFrame)
+	if err != nil {
+		return err
+	}
+	w.id = id
+	w.info = info
+	RegisterWidget(w)
+	return nil
+}
+
+func (w *Frame) SetBorderWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -borderwidth {%v}", w.id, width))
+}
+
+func (w *Frame) BorderWidth() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -borderwidth", w.id))
+	return r
+}
+
+func (w *Frame) SetReliefStyle(relief ReliefStyle) error {
+	return eval(fmt.Sprintf("%v configure -relief {%v}", w.id, relief))
+}
+
+func (w *Frame) ReliefStyle() ReliefStyle {
+	r, err := evalAsString(fmt.Sprintf("%v cget -relief", w.id))
+	return parserReliefStyleResult(r, err)
+}
+
+func (w *Frame) SetWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -width {%v}", w.id, width))
+}
+
+func (w *Frame) Width() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -width", w.id))
+	return r
+}
+
+func (w *Frame) SetHeight(height int) error {
+	return eval(fmt.Sprintf("%v configure -height {%v}", w.id, height))
+}
+
+func (w *Frame) Height() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -height", w.id))
+	return r
+}
+
+func (w *Frame) SetPaddingN(padx int, pady int) error {
+	if w.info.IsTtk {
+		return eval(fmt.Sprintf("%v configure -padding {%v %v}", w.id, padx, pady))
+	}
+	return eval(fmt.Sprintf("%v configure -padx {%v} -pady {%v}", w.id, padx, pady))
+}
+
+func (w *Frame) PaddingN() (int, int) {
+	var r string
+	var err error
+	if w.info.IsTtk {
+		r, err = evalAsString(fmt.Sprintf("%v cget -padding", w.id))
+	} else {
+		r1, _ := evalAsString(fmt.Sprintf("%v cget -padx", w.id))
+		r2, _ := evalAsString(fmt.Sprintf("%v cget -pady", w.id))
+		r = r1 + " " + r2
+	}
+	return parserPaddingResult(r, err)
+}
+
+func (w *Frame) SetPadding(pad Pad) error {
+	return w.SetPaddingN(pad.X, pad.Y)
+}
+
+func (w *Frame) Padding() Pad {
+	x, y := w.PaddingN()
+	return Pad{x, y}
+}
+
+func (w *Frame) SetTakeFocus(takefocus bool) error {
+	return eval(fmt.Sprintf("%v configure -takefocus {%v}", w.id, boolToInt(takefocus)))
+}
+
+func (w *Frame) IsTakeFocus() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -takefocus", w.id))
+	return r
+}
+
+func FrameAttrBorderWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"borderwidth", width}
+}
+
+func FrameAttrReliefStyle(relief ReliefStyle) *WidgetAttr {
+	return &WidgetAttr{"relief", relief}
+}
+
+func FrameAttrWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"width", width}
+}
+
+func FrameAttrHeight(height int) *WidgetAttr {
+	return &WidgetAttr{"height", height}
+}
+
+func FrameAttrPadding(pad Pad) *WidgetAttr {
+	return &WidgetAttr{"pad", pad}
+}
+
+func FrameAttrTakeFocus(takefocus bool) *WidgetAttr {
+	return &WidgetAttr{"takefocus", boolToInt(takefocus)}
+}

+ 167 - 0
vendor/github.com/visualfc/atk/tk/grid.go

@@ -0,0 +1,167 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+)
+
+func GridAttrColumn(n int) *LayoutAttr {
+	return &LayoutAttr{"column", n}
+}
+
+func GridAttrColumnSpan(n int) *LayoutAttr {
+	return &LayoutAttr{"columnspan", n}
+}
+
+func GridAttrRow(n int) *LayoutAttr {
+	return &LayoutAttr{"row", n}
+}
+
+func GridAttrRowSpan(n int) *LayoutAttr {
+	return &LayoutAttr{"rowspan", n}
+}
+
+func GridAttrInMaster(w Widget) *LayoutAttr {
+	if !IsValidWidget(w) {
+		return nil
+	}
+	return &LayoutAttr{"in", w.Id()}
+}
+
+func GridAttrIpadx(padx int) *LayoutAttr {
+	return &LayoutAttr{"ipadx", padx}
+}
+
+func GridAttrIpady(pady int) *LayoutAttr {
+	return &LayoutAttr{"ipady", pady}
+}
+
+func GridAttrPadx(padx int) *LayoutAttr {
+	return &LayoutAttr{"padx", padx}
+}
+
+func GridAttrPady(pady int) *LayoutAttr {
+	return &LayoutAttr{"pady", pady}
+}
+
+func GridAttrSticky(v Sticky) *LayoutAttr {
+	return &LayoutAttr{"sticky", v}
+}
+
+type GridIndexAttr struct {
+	key   string
+	value interface{}
+}
+
+func GridIndexAttrMinSize(amount int) *GridIndexAttr {
+	return &GridIndexAttr{"minsize", amount}
+}
+
+func GridIndexAttrPad(amount int) *GridIndexAttr {
+	return &GridIndexAttr{"pad", amount}
+}
+
+func GridIndexAttrWeight(value int) *GridIndexAttr {
+	return &GridIndexAttr{"weight", value}
+}
+
+func GridIndexAttrUniform(groupname string) *GridIndexAttr {
+	return &GridIndexAttr{"uniform", groupname}
+}
+
+func Grid(widget Widget, attributes ...*LayoutAttr) error {
+	return GridList([]Widget{widget}, attributes...)
+}
+
+func GridRemove(widget Widget) error {
+	if !IsValidWidget(widget) {
+		return ErrInvalid
+	}
+	return eval("grid forget " + widget.Id())
+}
+
+var (
+	gridAttrKeys = []string{
+		"column", "columnspan",
+		"row", "rowspan",
+		"in",
+		"ipadx", "ipady",
+		"padx", "pady",
+		"sticky",
+	}
+	gridIndexAttrKeys = []string{
+		"minsize",
+		"pad",
+		"weight",
+		"uniform",
+	}
+)
+
+func GridList(widgets []Widget, attributes ...*LayoutAttr) error {
+	var idList []string
+	for _, w := range widgets {
+		if IsValidWidget(w) {
+			w = checkLayoutWidget(w)
+			idList = append(idList, w.Id())
+		} else {
+			idList = append(idList, "x")
+		}
+	}
+	if len(idList) == 0 {
+		return ErrInvalid
+	}
+	var attrList []string
+	for _, attr := range attributes {
+		if attr == nil || !isValidKey(attr.key, gridAttrKeys) {
+			continue
+		}
+		attrList = append(attrList, fmt.Sprintf("-%v {%v}", attr.key, attr.value))
+	}
+	script := fmt.Sprintf("grid %v", strings.Join(idList, " "))
+	if len(attrList) > 0 {
+		script += " " + strings.Join(attrList, " ")
+	}
+	return eval(script)
+}
+
+// row index from 0; -1=all
+func GridRowIndex(master Widget, index int, attributes ...*GridIndexAttr) error {
+	return gridIndex(master, true, index, attributes)
+}
+
+// column index from 0; -1=all
+func GridColumnIndex(master Widget, index int, attributes ...*GridIndexAttr) error {
+	return gridIndex(master, false, index, attributes)
+}
+
+func gridIndex(master Widget, row bool, index int, attributes []*GridIndexAttr) error {
+	if master == nil {
+		master = rootWindow
+	}
+	var sindex string
+	if index < 0 {
+		sindex = "all"
+	} else {
+		sindex = strconv.Itoa(index)
+	}
+	var attrList []string
+	for _, attr := range attributes {
+		if attr == nil || !isValidKey(attr.key, gridIndexAttrKeys) {
+			continue
+		}
+		attrList = append(attrList, fmt.Sprintf("-%v {%v}", attr.key, attr.value))
+	}
+	var script string
+	if row {
+		script = fmt.Sprintf("grid rowconfigure %v %v", master.Id(), sindex)
+	} else {
+		script = fmt.Sprintf("grid columnconfigure %v %v", master.Id(), sindex)
+	}
+	if len(attrList) > 0 {
+		script += " " + strings.Join(attrList, " ")
+	}
+	return eval(script)
+}

+ 71 - 0
vendor/github.com/visualfc/atk/tk/gridlayout.go

@@ -0,0 +1,71 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import "fmt"
+
+type GridLayout struct {
+	*LayoutFrame
+	items []*LayoutItem
+}
+
+func (w *GridLayout) AddWidget(widget Widget, attrs ...*LayoutAttr) error {
+	if !IsValidWidget(widget) {
+		return ErrInvalid
+	}
+	return Grid(widget, AppendLayoutAttrs(attrs, GridAttrInMaster(w))...)
+}
+
+func (w *GridLayout) AddWidgets(widgets ...Widget) error {
+	return GridList(widgets, GridAttrInMaster(w))
+}
+
+func (w *GridLayout) AddWidgetList(widgets []Widget, attrs ...*LayoutAttr) error {
+	return GridList(widgets, AppendLayoutAttrs(attrs, GridAttrInMaster(w))...)
+}
+
+func (w *GridLayout) AddWidgetEx(widget Widget, row int, column int, rowspan int, columnspan int, sticky Sticky) error {
+	if !IsValidWidget(widget) {
+		return ErrInvalid
+	}
+	return Grid(widget, GridAttrRow(row), GridAttrColumn(column),
+		GridAttrRowSpan(rowspan), GridAttrColumnSpan(columnspan),
+		GridAttrSticky(sticky), GridAttrInMaster(w))
+}
+
+func (w *GridLayout) RemoveWidget(widget Widget) error {
+	if !IsValidWidget(widget) {
+		return ErrInvalid
+	}
+	return GridRemove(widget)
+}
+
+func (w *GridLayout) Repack() error {
+	return Pack(w, PackAttrFill(FillBoth), PackAttrExpand(true))
+}
+
+func (w *GridLayout) SetBorderWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -borderwidth {%v}", w.Id(), width))
+}
+
+func (w *GridLayout) BorderWidth() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -borderwidth", w.Id()))
+	return r
+}
+
+// row index from 0, -1=all
+func (w *GridLayout) SetRowAttr(row int, pad int, weight int, group string) error {
+	return GridRowIndex(w, row, GridIndexAttrPad(pad), GridIndexAttrWeight(weight), GridIndexAttrUniform(group))
+}
+
+// column index from 0, -1=all
+func (w *GridLayout) SetColumnAttr(column int, pad int, weight int, group string) error {
+	return GridColumnIndex(w, column, GridIndexAttrPad(pad), GridIndexAttrWeight(weight), GridIndexAttrUniform(group))
+}
+
+func NewGridLayout(parent Widget) *GridLayout {
+	grid := &GridLayout{NewLayoutFrame(parent), nil}
+	grid.Lower(nil)
+	grid.Repack()
+	return grid
+}

+ 121 - 0
vendor/github.com/visualfc/atk/tk/ids.go

@@ -0,0 +1,121 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+	"sync"
+)
+
+func NewGenInt64Func(id int64) func() <-chan int64 {
+	ch := make(chan int64)
+	go func(i int64) {
+		for {
+			i++
+			ch <- i
+		}
+	}(id)
+	return func() <-chan int64 {
+		return ch
+	}
+}
+
+func NewGenIntFunc(id int) func() <-chan int {
+	ch := make(chan int)
+	go func(i int) {
+		for {
+			i++
+			ch <- i
+		}
+	}(id)
+	return func() <-chan int {
+		return ch
+	}
+}
+
+type NamedId interface {
+	GetId(name string) string
+}
+
+type baseNamedId struct {
+	m map[string]int
+}
+
+func (m *baseNamedId) GetId(name string) (r string) {
+	m.m[name]++
+	r = fmt.Sprintf("%v%v", name, m.m[name])
+	return
+}
+
+type safeNamedId struct {
+	sync.Mutex
+	m map[string]int
+}
+
+func (m *safeNamedId) GetId(name string) (r string) {
+	m.Lock()
+	m.m[name]++
+	r = fmt.Sprintf("%v%v", name, m.m[name])
+	m.Unlock()
+	return
+}
+
+func NewNamedId(safe bool) NamedId {
+	if safe {
+		return &safeNamedId{m: make(map[string]int)}
+	}
+	return &baseNamedId{make(map[string]int)}
+}
+
+var (
+	atkNamedId = NewNamedId(false)
+)
+
+func makeNamedId(name string) string {
+	return atkNamedId.GetId(name)
+}
+
+func makeNamedWidgetId(parent Widget, typ string) string {
+	if parent == nil || parent.Id() == "." {
+		return makeNamedId("." + typ)
+	}
+	return makeNamedId(parent.Id() + "." + typ)
+}
+
+func makeActionId() string {
+	return makeNamedId("atk_action")
+}
+
+func makeBindEventId() string {
+	return makeNamedId("atk_bindevent")
+}
+
+func makeTreeItemId(treeid string, pid string) string {
+	if pid != "" {
+		return makeNamedId(pid + ".I")
+	}
+	return makeNamedId(treeid + ".I")
+}
+
+func variableId(id string) string {
+	return "::atk" + id + "_variable"
+}
+
+func evalSetValue(id string, value string) error {
+	return eval(fmt.Sprintf("set %v {%v}", id, value))
+}
+
+func evalGetValue(id string) string {
+	r, _ := evalAsString(fmt.Sprintf("set %v", id))
+	return r
+}
+
+func traceVariable(id string, fn func()) error {
+	act := makeActionId()
+	mainInterp.CreateAction(act, func(args []string) {
+		if fn != nil {
+			fn()
+		}
+	})
+	return eval(fmt.Sprintf("trace add variable %v write %v", id, act))
+}

+ 176 - 0
vendor/github.com/visualfc/atk/tk/image.go

@@ -0,0 +1,176 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"errors"
+	"fmt"
+	"image"
+	"image/color"
+	_ "image/png"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"github.com/visualfc/atk/tk/interp"
+)
+
+type Image struct {
+	id        string
+	photo     *interp.Photo
+	tk85alpha color.Color
+}
+
+func (i *Image) Id() string {
+	return i.id
+}
+
+type ImageAttr struct {
+	key   string
+	value interface{}
+}
+
+func ImageAttrGamma(gamma float64) *ImageAttr {
+	return &ImageAttr{"gamma", gamma}
+}
+
+func ImageAttrTk85AlphaColor(color color.Color) *ImageAttr {
+	return &ImageAttr{"tk85alphacolor", color}
+}
+
+func LoadImage(file string, attributes ...*ImageAttr) (*Image, error) {
+	if file == "" {
+		return nil, ErrInvalid
+	}
+	var fileImage image.Image
+	if filepath.Ext(file) == ".gif" {
+		attributes = append(attributes, &ImageAttr{"file", file})
+	} else {
+		file, err := os.Open(file)
+		if err != nil {
+			return nil, err
+		}
+		im, _, err := image.Decode(file)
+		file.Close()
+		if err != nil {
+			return nil, err
+		}
+		fileImage = im
+	}
+	im := NewImage(attributes...)
+	if im == nil {
+		return nil, errors.New("NewImage failed")
+	}
+	if fileImage != nil {
+		im.SetImage(fileImage)
+	}
+	return im, nil
+}
+
+func NewImage(attributes ...*ImageAttr) *Image {
+	var attrList []string
+	var tk85alphacolor color.Color
+	for _, attr := range attributes {
+		if attr == nil {
+			continue
+		}
+		if attr.key == "tk85alphacolor" {
+			if clr, ok := attr.value.(color.Color); ok {
+				tk85alphacolor = clr
+			}
+			continue
+		}
+		if s, ok := attr.value.(string); ok {
+			pname := "atk_tmp_" + attr.key
+			setObjText(pname, s)
+			attrList = append(attrList, fmt.Sprintf("-%v $%v", attr.key, pname))
+			continue
+		}
+		attrList = append(attrList, fmt.Sprintf("-%v {%v}", attr.key, attr.value))
+	}
+	iid := makeNamedId("atk_image")
+	script := fmt.Sprintf("image create photo %v", iid)
+	if len(attrList) > 0 {
+		script += " " + strings.Join(attrList, " ")
+	}
+	err := eval(script)
+	if err != nil {
+		return nil
+	}
+	photo := interp.FindPhoto(mainInterp, iid)
+	if photo == nil {
+		return nil
+	}
+	return &Image{iid, photo, tk85alphacolor}
+}
+
+func (i *Image) IsValid() bool {
+	return i.id != "" && i.photo != nil
+}
+
+func (i *Image) SetImage(img image.Image) *Image {
+	err := i.photo.PutImage(img, i.tk85alpha)
+	if err != nil {
+		dumpError(err)
+	}
+	return i
+}
+
+func (i *Image) SetZoomedImage(img image.Image, zoomX, zoomY, subsampleX, subsampleY int) *Image {
+	err := i.photo.PutZoomedImage(img, zoomX, zoomY, subsampleX, subsampleY, i.tk85alpha)
+	if err != nil {
+		dumpError(err)
+	}
+	return i
+}
+
+func (i *Image) ToImage() image.Image {
+	return i.photo.ToImage()
+}
+
+func (i *Image) Blank() *Image {
+	i.photo.Blank()
+	return i
+}
+
+func (i *Image) SizeN() (width int, height int) {
+	return i.photo.Size()
+}
+
+func (i *Image) Size() Size {
+	w, h := i.SizeN()
+	return Size{w, h}
+}
+
+func (i *Image) SetSizeN(width int, height int) *Image {
+	err := i.photo.SetSize(width, height)
+	if err != nil {
+		dumpError(err)
+	}
+	return i
+}
+
+func (i *Image) SetSize(sz Size) *Image {
+	return i.SetSizeN(sz.Width, sz.Height)
+}
+
+func (i *Image) Gamma() float64 {
+	v, _ := evalAsFloat64(fmt.Sprintf("%v cget -gamma", i.id))
+	return v
+}
+
+func (i *Image) SetGamma(v float64) *Image {
+	eval(fmt.Sprintf("%v configure -gamma {%v}", i.id, v))
+	return i
+}
+
+func parserImageResult(id string, err error) *Image {
+	if err != nil {
+		return nil
+	}
+	photo := interp.FindPhoto(mainInterp, id)
+	if photo == nil {
+		return nil
+	}
+	return &Image{id, photo, nil}
+}

+ 22 - 0
vendor/github.com/visualfc/atk/tk/interp/cbytes_go16_unix.go

@@ -0,0 +1,22 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+// +build !go1.7,!windows
+
+package interp
+
+import (
+	"unsafe"
+)
+
+/*
+#include <stdlib.h>
+#include <string.h>
+*/
+import "C"
+
+func toCBytes(data []byte) unsafe.Pointer {
+	size := C.size_t(len(data))
+	ptr := C.malloc(size)
+	C.memcpy(ptr, unsafe.Pointer(&data[0]), size)
+	return ptr
+}

+ 15 - 0
vendor/github.com/visualfc/atk/tk/interp/cbytes_unix.go

@@ -0,0 +1,15 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+// +build go1.7,!windows
+
+package interp
+
+import (
+	"unsafe"
+)
+
+import "C"
+
+func toCBytes(data []byte) unsafe.Pointer {
+	return C.CBytes(data)
+}

+ 281 - 0
vendor/github.com/visualfc/atk/tk/interp/interp.go

@@ -0,0 +1,281 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package interp
+
+import (
+	"errors"
+	"strconv"
+)
+
+const (
+	TCL_OK    = 0
+	TCL_ERROR = 1
+)
+
+type Tcl_QueuePosition int
+
+const (
+	TCL_QUEUE_TAIL Tcl_QueuePosition = 0
+	TCL_QUEUE_HEAD
+	TCL_QUEUE_MARK
+)
+
+const (
+	TCL_DONT_WAIT     = 1 << 1
+	TCL_WINDOW_EVENTS = 1 << 2
+	TCL_FILE_EVENTS   = 1 << 3
+	TCL_TIMER_EVENTS  = 1 << 4
+	TCL_IDLE_EVENTS   = 1 << 5
+	TCL_ALL_EVENTS    = ^TCL_DONT_WAIT
+)
+
+var (
+	globalCommandMap = NewCommandMap()
+	globalActionMap  = NewActionMap()
+)
+
+type ActionMap struct {
+	fnMap map[uintptr]func([]string)
+	id    uintptr
+}
+
+func NewActionMap() *ActionMap {
+	return &ActionMap{make(map[uintptr]func([]string)), 1}
+}
+
+func (m *ActionMap) Register(fn func([]string)) uintptr {
+	m.id = m.id + 1
+	m.fnMap[m.id] = fn
+	return m.id
+}
+
+func (m *ActionMap) UnRegister(id uintptr) {
+	delete(m.fnMap, id)
+}
+
+func (m *ActionMap) Invoke(id uintptr, args []string) error {
+	fn, ok := m.fnMap[id]
+	if !ok {
+		return errors.New("Not found action")
+	}
+	fn(args)
+	return nil
+}
+
+type CommandMap struct {
+	fnMap map[uintptr]func([]string) (string, error)
+	id    uintptr
+}
+
+func (m *CommandMap) Register(fn func([]string) (string, error)) uintptr {
+	m.id = m.id + 1
+	m.fnMap[m.id] = fn
+	return m.id
+}
+
+func (m *CommandMap) UnRegister(id uintptr) {
+	delete(m.fnMap, id)
+}
+
+func (m *CommandMap) Find(id uintptr) func([]string) (string, error) {
+	return m.fnMap[id]
+}
+
+func (m *CommandMap) Invoke(id uintptr, args []string) (string, error) {
+	fn, ok := m.fnMap[id]
+	if !ok {
+		return "", errors.New("Not found command")
+	}
+	return fn(args)
+}
+
+func NewCommandMap() *CommandMap {
+	return &CommandMap{make(map[uintptr]func([]string) (string, error)), 1}
+}
+
+func (interp *Interp) EvalAsString(script string) (string, error) {
+	err := interp.Eval(script)
+	if err != nil {
+		return "", err
+	}
+	return interp.GetStringResult(), nil
+}
+
+func (interp *Interp) EvalAsInt64(script string) (int64, error) {
+	err := interp.Eval(script)
+	if err != nil {
+		return 0, err
+	}
+	return interp.GetInt64Result(), nil
+}
+
+func (interp *Interp) EvalAsInt(script string) (int, error) {
+	err := interp.Eval(script)
+	if err != nil {
+		return 0, err
+	}
+	return interp.GetIntResult(), nil
+}
+
+func (interp *Interp) EvalAsUint(script string) (uint, error) {
+	err := interp.Eval(script)
+	if err != nil {
+		return 0, err
+	}
+	return interp.GetUintResult(), nil
+}
+
+func (interp *Interp) EvalAsFloat64(script string) (float64, error) {
+	err := interp.Eval(script)
+	if err != nil {
+		return 0, err
+	}
+	return interp.GetFloat64Result(), nil
+}
+
+func (interp *Interp) EvalAsBool(script string) (bool, error) {
+	err := interp.Eval(script)
+	if err != nil {
+		return false, err
+	}
+	return interp.GetBoolResult(), nil
+}
+
+func (interp *Interp) EvalAsObj(script string) (*Obj, error) {
+	err := interp.Eval(script)
+	if err != nil {
+		return nil, err
+	}
+	return interp.GetObjResult(), nil
+}
+
+func (interp *Interp) EvalAsListObj(script string) (*ListObj, error) {
+	err := interp.Eval(script)
+	if err != nil {
+		return nil, err
+	}
+	return interp.GetListObjResult(), nil
+}
+
+func (interp *Interp) EvalAsStringList(script string) ([]string, error) {
+	err := interp.Eval(script)
+	if err != nil {
+		return nil, err
+	}
+	return interp.GetListObjResult().ToStringList(), nil
+}
+
+func (interp *Interp) EvalAsIntList(script string) ([]int, error) {
+	err := interp.Eval(script)
+	if err != nil {
+		return nil, err
+	}
+	return interp.GetListObjResult().ToIntList(), nil
+}
+
+func (interp *Interp) TclVersion() string {
+	ver, _ := interp.EvalAsString("set tcl_version")
+	return ver
+}
+
+func (interp *Interp) TclPatchLevel() string {
+	ver, _ := interp.EvalAsString("set tcl_patchLevel")
+	return ver
+}
+
+func (interp *Interp) TkVersion() string {
+	ver, _ := interp.EvalAsString("set tk_version")
+	return ver
+}
+
+func (interp *Interp) TkPatchLevel() string {
+	ver, _ := interp.EvalAsString("set tk_patchLevel")
+	return ver
+}
+
+func (p *Interp) GetStringResult() string {
+	return p.GetObjResult().ToString()
+}
+
+func (p *Interp) GetIntResult() int {
+	return p.GetObjResult().ToInt()
+}
+
+func (p *Interp) GetUintResult() uint {
+	return p.GetObjResult().ToUint()
+}
+
+func (p *Interp) GetInt64Result() int64 {
+	return p.GetObjResult().ToInt64()
+}
+
+func (p *Interp) GetFloat64Result() float64 {
+	return p.GetObjResult().ToFloat64()
+}
+
+func (p *Interp) GetBoolResult() bool {
+	return p.GetObjResult().ToBool()
+}
+
+func (p *Interp) GetErrorResult() error {
+	return errors.New(p.GetObjResult().ToString())
+}
+
+func (p *Interp) GetStringVar(name string, global bool) string {
+	obj := p.GetVar(name, global)
+	if obj == nil {
+		return ""
+	}
+	return obj.ToString()
+}
+
+func (p *Interp) GetIntVar(name string, global bool) int {
+	obj := p.GetVar(name, global)
+	if obj == nil {
+		return 0
+	}
+	return obj.ToInt()
+}
+
+func (p *Interp) GetInt64Var(name string, global bool) int64 {
+	obj := p.GetVar(name, global)
+	if obj == nil {
+		return 0
+	}
+	return obj.ToInt64()
+}
+
+func (p *Interp) GetFloadt64Var(name string, global bool) float64 {
+	obj := p.GetVar(name, global)
+	if obj == nil {
+		return 0
+	}
+	return obj.ToFloat64()
+}
+
+func (p *Interp) GetBoolVar(name string, global bool) bool {
+	obj := p.GetVar(name, global)
+	if obj == nil {
+		return false
+	}
+	return obj.ToBool()
+}
+
+func (p *Interp) SetIntVar(name string, value int, global bool) error {
+	return p.SetStringVar(name, strconv.Itoa(value), global)
+}
+
+func (p *Interp) SetInt64Var(name string, value int64, global bool) error {
+	return p.SetStringVar(name, strconv.FormatInt(value, 10), global)
+}
+
+func (p *Interp) SetFloat64Var(name string, value float64, global bool) error {
+	return p.SetStringVar(name, strconv.FormatFloat(value, 'E', -1, 64), global)
+}
+
+func (p *Interp) SetBoolVar(name string, b bool, global bool) error {
+	if b {
+		return p.SetStringVar(name, "1", global)
+	}
+	return p.SetStringVar(name, "0", global)
+}

+ 756 - 0
vendor/github.com/visualfc/atk/tk/interp/interp_unix.go

@@ -0,0 +1,756 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+//go:build !windows
+// +build !windows
+
+package interp
+
+import (
+	"errors"
+	"fmt"
+	"image"
+	"image/color"
+	"image/draw"
+	"os"
+	"unsafe"
+)
+
+/*
+#cgo darwin CFLAGS: -I/Library/Frameworks/Tcl.framework/Headers -I/Library/Frameworks/Tk.framework/Headers
+#cgo darwin LDFLAGS: -F/Library/Frameworks -framework tcl -framework tk
+#cgo linux CFLAGS: -I/usr/include/tcl
+#cgo linux LDFLAGS: -ltcl -ltk -lX11 -lm -lz -ldl
+
+#include <tcl.h>
+#include <tk.h>
+#include <stdlib.h>
+
+extern int _go_async_event_handler(Tcl_Event*, int);
+
+static Tcl_Event* _c_create_async_event()
+{
+	Tcl_Event *ev = (Tcl_Event*)Tcl_Alloc(sizeof(Tcl_Event));
+	ev->proc = &_go_async_event_handler;
+	ev->nextPtr = 0;
+	return ev;
+}
+
+static void _c_send_async_event(Tcl_ThreadId tid, Tcl_Event *ev)
+{
+	Tcl_ThreadQueueEvent(tid, ev, TCL_QUEUE_TAIL);
+	Tcl_ThreadAlert(tid);
+}
+
+extern  int _go_tcl_objcmd_proc(void *clientData, Tcl_Interp *interp, int objc, void *objv);
+extern void _go_tcl_deletecmd_proc(void *clientData);
+static  int _c_tcl_objcmd_proc(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
+{
+	return _go_tcl_objcmd_proc(clientData, interp, objc, (Tcl_Obj**)objv);
+}
+static Tcl_Command _c_create_obj_command(Tcl_Interp *interp, char *name, void* clientData)
+{
+	return Tcl_CreateObjCommand(interp,name,_c_tcl_objcmd_proc,clientData,&_go_tcl_deletecmd_proc);
+}
+
+extern  int _go_tcl_actioncmd_proc(void *clientData, Tcl_Interp *interp, int objc, void *objv);
+extern void _go_tcl_deleteaction_proc(void *clientData);
+static  int _c_tcl_actioncmd_proc(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
+{
+	return _go_tcl_actioncmd_proc(clientData, interp, objc, (Tcl_Obj**)objv);
+}
+static Tcl_Command _c_create_action_command(Tcl_Interp *interp, char *name, void* clientData)
+{
+	return Tcl_CreateObjCommand(interp,name,_c_tcl_actioncmd_proc,clientData,&_go_tcl_deleteaction_proc);
+}
+
+static void _c_wrong_num_args(Tcl_Interp *interp, int objc, void *objv, char *message)
+{
+	Tcl_WrongNumArgs(interp, objc, (Tcl_Obj**)objv, message)	;
+}
+
+*/
+import "C"
+
+var (
+	mainLoopThreadId C.Tcl_ThreadId
+)
+
+//export _go_tcl_objcmd_proc
+func _go_tcl_objcmd_proc(clientData unsafe.Pointer, interp *C.Tcl_Interp, objc C.int, objv unsafe.Pointer) C.int {
+	objs := (*(*[1 << 20]*C.Tcl_Obj)(objv))[1:objc:objc]
+	var args []string
+	for _, obj := range objs {
+		args = append(args, objToString(interp, obj))
+	}
+	result, err := globalCommandMap.Invoke(uintptr(clientData), args)
+	if err != nil {
+		cs := C.CString(err.Error())
+		defer C.free(unsafe.Pointer(cs))
+		C._c_wrong_num_args(interp, 1, objv, cs)
+		return TCL_ERROR
+	}
+	if result != "" {
+		C.Tcl_SetObjResult(interp, stringToObj(result))
+	}
+	return TCL_OK
+}
+
+//export _go_tcl_deletecmd_proc
+func _go_tcl_deletecmd_proc(clientData unsafe.Pointer) {
+	globalCommandMap.UnRegister(uintptr(clientData))
+	return
+}
+
+//export _go_tcl_actioncmd_proc
+func _go_tcl_actioncmd_proc(clientData unsafe.Pointer, interp *C.Tcl_Interp, objc C.int, objv unsafe.Pointer) C.int {
+	objs := (*(*[1 << 20]*C.Tcl_Obj)(objv))[1:objc:objc]
+	var args []string
+	for _, obj := range objs {
+		args = append(args, objToString(interp, obj))
+	}
+	err := globalActionMap.Invoke(uintptr(clientData), args)
+	if err != nil {
+		cs := C.CString(err.Error())
+		defer C.free(unsafe.Pointer(cs))
+		C._c_wrong_num_args(interp, 1, objv, cs)
+		return TCL_ERROR
+	}
+	return TCL_OK
+}
+
+//export _go_tcl_deleteaction_proc
+func _go_tcl_deleteaction_proc(clientData unsafe.Pointer) {
+	globalActionMap.UnRegister(uintptr(clientData))
+	return
+}
+
+//export _go_async_event_handler
+func _go_async_event_handler(ev *C.Tcl_Event, flags C.int) C.int {
+	if flags != C.TK_ALL_EVENTS {
+		return 0
+	}
+	if fn, ok := globalAsyncEvent.Load(unsafe.Pointer(ev)); ok {
+		fn.(func())()
+		globalAsyncEvent.Delete(unsafe.Pointer(ev))
+	}
+	return 1
+}
+
+func IsMainThread() bool {
+	return C.Tcl_GetCurrentThread() == mainLoopThreadId
+}
+
+func async_send_event(tid C.Tcl_ThreadId, fn func()) {
+	ev := C._c_create_async_event()
+	globalAsyncEvent.Store(unsafe.Pointer(ev), fn)
+	C._c_send_async_event(tid, ev)
+}
+
+func Async(fn func()) {
+	if fn == nil {
+		return
+	}
+	async_send_event(mainLoopThreadId, fn)
+}
+
+func MainLoop(fn func()) {
+	mainLoopThreadId = C.Tcl_GetCurrentThread()
+	if fn != nil {
+		fn()
+	}
+	C.Tk_MainLoop()
+	mainLoopThreadId = nil
+}
+
+type Interp struct {
+	interp      *C.Tcl_Interp
+	supportTk86 bool
+}
+
+func NewInterp() (*Interp, error) {
+	interp := C.Tcl_CreateInterp()
+	if interp == nil {
+		return nil, errors.New("Tcl_CreateInterp failed")
+	}
+	return &Interp{interp, false}, nil
+}
+
+func (p *Interp) SupportTk86() bool {
+	return p.supportTk86
+}
+
+func (p *Interp) InitTcl(tcl_library string) error {
+	if tcl_library != "" {
+		p.Eval(fmt.Sprintf("set tcl_library {%s}", tcl_library))
+	}
+	if C.Tcl_Init(p.interp) != TCL_OK {
+		err := errors.New("Tcl_Init failed")
+		return err
+	}
+	return nil
+}
+
+func (p *Interp) InitTk(tk_library string) error {
+	if tk_library != "" {
+		p.Eval(fmt.Sprintf("set tk_library {%s}", tk_library))
+	}
+	if C.Tk_Init(p.interp) != TCL_OK {
+		err := errors.New("Tk_Init failed")
+		return err
+	}
+	p.supportTk86 = p.TkVersion() >= "8.6"
+	return nil
+}
+
+func (p *Interp) Destroy() error {
+	if p == nil || p.interp == nil {
+		return os.ErrInvalid
+	}
+	C.Tcl_DeleteInterp(p.interp)
+	p.interp = nil
+	return nil
+}
+
+func (p *Interp) GetObjResult() *Obj {
+	return &Obj{C.Tcl_GetObjResult(p.interp), p.interp}
+}
+
+func (p *Interp) GetListObjResult() *ListObj {
+	return &ListObj{C.Tcl_GetObjResult(p.interp), p.interp}
+}
+
+func (p *Interp) Eval(script string) error {
+	cs := C.CString(script)
+	defer C.free(unsafe.Pointer(cs))
+	if C.Tcl_EvalEx(p.interp, cs, C.int(len(script)), 0) != TCL_OK {
+		err := errors.New(p.GetStringResult())
+		return err
+	}
+	return nil
+}
+
+func (p *Interp) CreateCommand(name string, fn func([]string) (string, error)) (uintptr, error) {
+	cs := C.CString(name)
+	defer C.free(unsafe.Pointer(cs))
+
+	id := globalCommandMap.Register(fn)
+	cmd := C._c_create_obj_command(p.interp, cs, unsafe.Pointer(id))
+	if cmd == nil {
+		err := fmt.Errorf("CreateCommand %v failed", name)
+		return 0, err
+	}
+	return id, nil
+}
+
+func (p *Interp) InvokeCommand(id uintptr, args []string) (string, error) {
+	return globalCommandMap.Invoke(id, args)
+}
+
+func (p *Interp) CreateAction(name string, fn func([]string)) (uintptr, error) {
+	cs := C.CString(name)
+	defer C.free(unsafe.Pointer(cs))
+
+	id := globalActionMap.Register(fn)
+	cmd := C._c_create_action_command(p.interp, cs, unsafe.Pointer(id))
+	if cmd == nil {
+		err := fmt.Errorf("CreateAction %v failed", name)
+		return 0, err
+	}
+	return id, nil
+}
+
+func (p *Interp) InvokeAction(id uintptr, args []string) error {
+	return globalActionMap.Invoke(id, args)
+}
+
+func (p *Interp) GetVar(name string, global bool) *Obj {
+	cname := C.CString(name)
+	defer C.free(unsafe.Pointer(cname))
+	var flag C.int = C.TCL_LEAVE_ERR_MSG
+	if global {
+		flag |= C.TCL_GLOBAL_ONLY
+	}
+	obj := C.Tcl_GetVar2Ex(p.interp, cname, nil, flag)
+	if obj == nil {
+		return nil
+	}
+	return &Obj{obj, p.interp}
+}
+
+func (p *Interp) GetList(name string, global bool) *ListObj {
+	return (*ListObj)(p.GetVar(name, global))
+}
+
+func (p *Interp) SetStringList(name string, list []string, global bool) error {
+	obj := NewListObj(p)
+	obj.AppendStringList(list)
+	return p.SetVarObj(name, (*Obj)(obj), global)
+}
+
+func (p *Interp) AppendStringListList(name string, list []string, global bool) error {
+	cname := C.CString(name)
+	defer C.free(unsafe.Pointer(cname))
+	var flag C.int = C.TCL_LEAVE_ERR_MSG | C.TCL_APPEND_VALUE | C.TCL_LIST_ELEMENT
+	if global {
+		flag |= C.TCL_GLOBAL_ONLY
+	}
+	for _, value := range list {
+		cvalue := C.CString(value)
+		C.Tcl_SetVar(p.interp, cname, cvalue, flag)
+		C.free(unsafe.Pointer(cvalue))
+	}
+	return nil
+}
+
+func (p *Interp) AppendStringList(name string, value string, global bool) error {
+	cname := C.CString(name)
+	defer C.free(unsafe.Pointer(cname))
+	cvalue := C.CString(value)
+	defer C.free(unsafe.Pointer(cvalue))
+	var flag C.int = C.TCL_LEAVE_ERR_MSG | C.TCL_APPEND_VALUE | C.TCL_LIST_ELEMENT
+	if global {
+		flag |= C.TCL_GLOBAL_ONLY
+	}
+	r := C.Tcl_SetVar(p.interp, cname, cvalue, flag)
+	if r == nil {
+		return p.GetErrorResult()
+	}
+	return nil
+}
+
+func (p *Interp) SetVarObj(name string, obj *Obj, global bool) error {
+	if obj == nil {
+		return os.ErrInvalid
+	}
+	cname := C.CString(name)
+	defer C.free(unsafe.Pointer(cname))
+	var flag C.int = C.TCL_LEAVE_ERR_MSG
+	if global {
+		flag |= C.TCL_GLOBAL_ONLY
+	}
+	r := C.Tcl_SetVar2Ex(p.interp, cname, nil, obj.obj, flag)
+	if r == nil {
+		return p.GetErrorResult()
+	}
+	return nil
+}
+
+func (p *Interp) SetVarListObj(name string, obj *ListObj, global bool) error {
+	return p.SetVarObj(name, (*Obj)(obj), global)
+}
+
+func (p *Interp) SetStringVar(name string, value string, global bool) error {
+	cname := C.CString(name)
+	defer C.free(unsafe.Pointer(cname))
+	cvalue := C.CString(value)
+	defer C.free(unsafe.Pointer(cvalue))
+	var flag C.int = C.TCL_LEAVE_ERR_MSG
+	if global {
+		flag |= C.TCL_GLOBAL_ONLY
+	}
+	r := C.Tcl_SetVar(p.interp, cname, cvalue, flag)
+	if r == nil {
+		return p.GetErrorResult()
+	}
+	return nil
+}
+
+func (p *Interp) AppendStringVar(name string, value string, global bool) error {
+	cname := C.CString(name)
+	defer C.free(unsafe.Pointer(cname))
+	cvalue := C.CString(value)
+	defer C.free(unsafe.Pointer(cvalue))
+	var flag C.int = C.TCL_LEAVE_ERR_MSG | C.TCL_APPEND_VALUE
+	if global {
+		flag |= C.TCL_GLOBAL_ONLY
+	}
+	r := C.Tcl_SetVar(p.interp, cname, cvalue, flag)
+	if r == nil {
+		return p.GetErrorResult()
+	}
+	return nil
+}
+
+func (p *Interp) UnsetVar(name string, global bool) error {
+	cname := C.CString(name)
+	defer C.free(unsafe.Pointer(cname))
+	var flag C.int = C.TCL_LEAVE_ERR_MSG
+	if global {
+		flag |= C.TCL_GLOBAL_ONLY
+	}
+	r := C.Tcl_UnsetVar(p.interp, cname, flag)
+	if r != C.TCL_OK {
+		return p.GetErrorResult()
+	}
+	return nil
+}
+
+type Obj struct {
+	obj    *C.Tcl_Obj
+	interp *C.Tcl_Interp
+}
+
+func (o *Obj) ToFloat64() float64 {
+	var out C.double
+	status := C.Tcl_GetDoubleFromObj(o.interp, o.obj, &out)
+	if status == C.TCL_OK {
+		return float64(out)
+	}
+	return 0
+}
+
+func (o *Obj) ToInt64() int64 {
+	var out C.Tcl_WideInt
+	status := C.Tcl_GetWideIntFromObj(o.interp, o.obj, &out)
+	if status == TCL_OK {
+		return int64(out)
+	}
+	return 0
+}
+
+func (o *Obj) ToInt() int {
+	return int(o.ToInt64())
+}
+
+func (o *Obj) ToUint() uint {
+	return uint(o.ToInt64())
+}
+
+func (o *Obj) ToBool() bool {
+	var out C.int
+	status := C.Tcl_GetBooleanFromObj(o.interp, o.obj, &out)
+	if status == C.TCL_OK {
+		return out == 1
+	}
+	return false
+}
+
+func (o *Obj) ToString() string {
+	var n C.int
+	out := C.Tcl_GetStringFromObj(o.obj, &n)
+	return C.GoStringN(out, n)
+}
+
+func NewStringObj(value string, p *Interp) *Obj {
+	cs := C.CString(value)
+	defer C.free(unsafe.Pointer(cs))
+	return &Obj{C.Tcl_NewStringObj(cs, C.int(len(value))), p.interp}
+}
+
+func NewFloat64Obj(value float64, p *Interp) *Obj {
+	return &Obj{C.Tcl_NewDoubleObj(C.double(value)), p.interp}
+}
+
+func NewInt64Obj(value int64, p *Interp) *Obj {
+	return &Obj{C.Tcl_NewWideIntObj(C.Tcl_WideInt(value)), p.interp}
+}
+
+func NewIntObj(value int, p *Interp) *Obj {
+	return &Obj{C.Tcl_NewWideIntObj(C.Tcl_WideInt(value)), p.interp}
+}
+
+func NewBoolObj(value bool, p *Interp) *Obj {
+	if value {
+		return &Obj{C.Tcl_NewBooleanObj(1), p.interp}
+	} else {
+		return &Obj{C.Tcl_NewBooleanObj(0), p.interp}
+	}
+}
+
+func objToString(interp *C.Tcl_Interp, obj *C.Tcl_Obj) string {
+	var n C.int
+	out := C.Tcl_GetStringFromObj(obj, &n)
+	return C.GoStringN(out, n)
+}
+
+func stringToObj(value string) *C.Tcl_Obj {
+	cs := C.CString(value)
+	defer C.free(unsafe.Pointer(cs))
+	return C.Tcl_NewStringObj(cs, C.int(len(value)))
+}
+
+type ListObj Obj
+
+func NewListObj(p *Interp) *ListObj {
+	o := C.Tcl_NewListObj(0, nil)
+	return &ListObj{o, p.interp}
+}
+
+func (o *ListObj) Length() int {
+	var length C.int
+	C.Tcl_ListObjLength(o.interp, o.obj, &length)
+	return int(length)
+}
+
+func (o *ListObj) IndexObj(index int) *Obj {
+	var obj *C.Tcl_Obj
+	r := C.Tcl_ListObjIndex(o.interp, o.obj, C.int(index), &obj)
+	if r != C.TCL_OK || obj == nil {
+		return nil
+	}
+	return &Obj{obj, o.interp}
+}
+
+func (o *ListObj) IndexString(index int) string {
+	var obj *C.Tcl_Obj
+	r := C.Tcl_ListObjIndex(o.interp, o.obj, C.int(index), &obj)
+	if r != C.TCL_OK || obj == nil {
+		return ""
+	}
+	return objToString(o.interp, obj)
+}
+
+func (o *ListObj) ToObjList() (list []*Obj) {
+	var objs **C.Tcl_Obj
+	var objnum C.int
+	C.Tcl_ListObjGetElements(o.interp, o.obj, &objnum, &objs)
+	if objnum == 0 {
+		return
+	}
+	lst := (*[1 << 28]*C.Tcl_Obj)(unsafe.Pointer(objs))[:int(objnum):int(objnum)]
+	for _, v := range lst {
+		list = append(list, &Obj{v, o.interp})
+	}
+	return
+}
+
+func (o *ListObj) ToStringList() (list []string) {
+	var objs **C.Tcl_Obj
+	var objnum C.int
+	C.Tcl_ListObjGetElements(o.interp, o.obj, &objnum, &objs)
+	if objnum == 0 {
+		return
+	}
+	lst := (*[1 << 28]*C.Tcl_Obj)(unsafe.Pointer(objs))[:int(objnum):int(objnum)]
+	var n C.int
+	for _, obj := range lst {
+		out := C.Tcl_GetStringFromObj(obj, &n)
+		list = append(list, C.GoStringN(out, n))
+	}
+	return
+}
+
+func (o *ListObj) ToIntList() (list []int) {
+	var objs **C.Tcl_Obj
+	var objnum C.int
+	C.Tcl_ListObjGetElements(o.interp, o.obj, &objnum, &objs)
+	if objnum == 0 {
+		return
+	}
+	lst := (*[1 << 28]*C.Tcl_Obj)(unsafe.Pointer(objs))[:int(objnum):int(objnum)]
+	var out C.Tcl_WideInt
+	for _, obj := range lst {
+		C.Tcl_GetWideIntFromObj(o.interp, obj, &out)
+		list = append(list, int(out))
+	}
+	return
+}
+
+func (o *ListObj) SetStringList(list []string) {
+	C.Tcl_SetListObj(o.obj, 0, nil)
+	o.AppendStringList(list)
+}
+
+func (o *ListObj) AppendStringList(list []string) {
+	for _, v := range list {
+		cs := C.CString(v)
+		obj := C.Tcl_NewStringObj(cs, C.int(len(v)))
+		C.Tcl_ListObjAppendElement(o.interp, o.obj, obj)
+		C.free(unsafe.Pointer(cs))
+	}
+}
+
+func (o *ListObj) AppendObj(obj *Obj) bool {
+	if obj == nil {
+		return false
+	}
+	C.Tcl_ListObjAppendElement(o.interp, o.obj, obj.obj)
+	return true
+}
+
+func (o *ListObj) AppendString(s string) {
+	C.Tcl_ListObjAppendElement(o.interp, o.obj, stringToObj(s))
+}
+
+func (o *ListObj) InsertObj(index int, obj *Obj) {
+	C.Tcl_ListObjReplace(o.interp, o.obj, C.int(index), 0, 1, &obj.obj)
+}
+
+func (o *ListObj) InsertString(index int, s string) {
+	obj := stringToObj(s)
+	C.Tcl_ListObjReplace(o.interp, o.obj, C.int(index), 0, 1, &obj)
+}
+
+func (o *ListObj) SetIndexObj(index int, obj *Obj) bool {
+	if obj == nil {
+		return false
+	}
+	C.Tcl_ListObjReplace(o.interp, o.obj, C.int(index), 1, 1, &obj.obj)
+	return true
+}
+
+func (o *ListObj) SetIndexString(index int, s string) {
+	obj := stringToObj(s)
+	C.Tcl_ListObjReplace(o.interp, o.obj, C.int(index), 1, 1, &obj)
+}
+
+func (o *ListObj) Remove(first int, count int) {
+	C.Tcl_ListObjReplace(o.interp, o.obj, C.int(first), C.int(count), 0, nil)
+}
+
+type Photo struct {
+	handle C.Tk_PhotoHandle
+	interp *Interp
+}
+
+func FindPhoto(interp *Interp, imageName string) *Photo {
+	cs := C.CString(imageName)
+	defer C.free(unsafe.Pointer(cs))
+	handle := C.Tk_FindPhoto(interp.interp, cs)
+	if handle == nil {
+		return nil
+	}
+	return &Photo{handle, interp}
+}
+
+func (p *Photo) Blank() {
+	C.Tk_PhotoBlank(p.handle)
+}
+
+func (p *Photo) SetSize(width int, height int) error {
+	status := C.Tk_PhotoSetSize(p.interp.interp, p.handle, C.int(width), C.int(height))
+	if status != C.TCL_OK {
+		return p.interp.GetErrorResult()
+	}
+	return nil
+}
+
+func (p *Photo) Size() (int, int) {
+	var width, height C.int
+	C.Tk_PhotoGetSize(p.handle, &width, &height)
+	return int(width), int(height)
+}
+
+func (p *Photo) Expand(width int, height int) error {
+	status := C.Tk_PhotoExpand(p.interp.interp, p.handle, C.int(width), C.int(height))
+	if status != C.TCL_OK {
+		return p.interp.GetErrorResult()
+	}
+	return nil
+}
+
+func (p *Photo) ToImage() image.Image {
+	var block C.Tk_PhotoImageBlock
+	C.Tk_PhotoGetImage(p.handle, &block)
+	if block.width == 0 || block.height == 0 {
+		return nil
+	}
+	r := image.Rect(0, 0, int(block.width), int(block.height))
+	pix := C.GoBytes(unsafe.Pointer(block.pixelPtr), C.int(4*block.width*block.height))
+	return &image.NRGBA{pix, 4 * int(block.width), r}
+}
+
+func (p *Photo) PutImage(img image.Image, tk85alphacolor color.Color) error {
+	if img == nil || img.Bounds().Empty() {
+		return os.ErrInvalid
+	}
+	var pixelPtr unsafe.Pointer
+	var stride int
+	if p.interp.supportTk86 {
+		dstImage, ok := img.(*image.NRGBA)
+		if !ok {
+			dstImage = image.NewNRGBA(img.Bounds())
+			draw.Draw(dstImage, dstImage.Bounds(), img, img.Bounds().Min, draw.Src)
+		}
+		stride = dstImage.Stride
+		pixelPtr = toCBytes(dstImage.Pix)
+	} else {
+		var r, g, b uint8
+		if tk85alphacolor != nil {
+			clr := color.RGBAModel.Convert(tk85alphacolor).(color.RGBA)
+			r, g, b = clr.R, clr.G, clr.B
+		}
+		dstImage := image.NewRGBA(img.Bounds())
+		for i := 0; i < len(dstImage.Pix); i += 4 {
+			dstImage.Pix[i+0] = r
+			dstImage.Pix[i+1] = g
+			dstImage.Pix[i+2] = b
+			dstImage.Pix[i+3] = 0xff
+		}
+		draw.Draw(dstImage, dstImage.Bounds(), img, img.Bounds().Min, draw.Over)
+		stride = dstImage.Stride
+		pixelPtr = toCBytes(dstImage.Pix)
+	}
+	defer C.free(pixelPtr)
+	width := img.Bounds().Dx()
+	height := img.Bounds().Dy()
+	offset := [4]C.int{0, 1, 2, 3}
+	block := C.Tk_PhotoImageBlock{
+		(*C.uchar)(pixelPtr),
+		C.int(width),
+		C.int(height),
+		C.int(stride),
+		4,
+		offset,
+	}
+	status := C.Tk_PhotoPutBlock(p.interp.interp, p.handle, &block,
+		0, 0, C.int(width), C.int(height),
+		C.TK_PHOTO_COMPOSITE_SET)
+	if status != C.TCL_OK {
+		return p.interp.GetErrorResult()
+	}
+	return nil
+}
+
+func (p *Photo) PutZoomedImage(img image.Image, zoomX, zoomY, subsampleX, subsampleY int, tk85alphacolor color.Color) error {
+	if img == nil || img.Bounds().Empty() {
+		return os.ErrInvalid
+	}
+	var pixelPtr unsafe.Pointer
+	var stride int
+	if p.interp.supportTk86 {
+		dstImage, ok := img.(*image.NRGBA)
+		if !ok {
+			dstImage = image.NewNRGBA(img.Bounds())
+			draw.Draw(dstImage, dstImage.Bounds(), img, img.Bounds().Min, draw.Src)
+		}
+		stride = dstImage.Stride
+		pixelPtr = toCBytes(dstImage.Pix)
+	} else {
+		var r, g, b uint8
+		if tk85alphacolor != nil {
+			clr := color.RGBAModel.Convert(tk85alphacolor).(color.RGBA)
+			r, g, b = clr.R, clr.G, clr.B
+		}
+		dstImage := image.NewRGBA(img.Bounds())
+		for i := 0; i < len(dstImage.Pix); i += 4 {
+			dstImage.Pix[i+0] = r
+			dstImage.Pix[i+1] = g
+			dstImage.Pix[i+2] = b
+			dstImage.Pix[i+3] = 0xff
+		}
+		draw.Draw(dstImage, dstImage.Bounds(), img, img.Bounds().Min, draw.Over)
+		stride = dstImage.Stride
+		pixelPtr = toCBytes(dstImage.Pix)
+	}
+	defer C.free(pixelPtr)
+	width := img.Bounds().Dx()
+	height := img.Bounds().Dy()
+	offset := [4]C.int{0, 1, 2, 3}
+	block := C.Tk_PhotoImageBlock{
+		(*C.uchar)(pixelPtr),
+		C.int(width),
+		C.int(height),
+		C.int(stride),
+		4,
+		offset,
+	}
+	status := C.Tk_PhotoPutZoomedBlock(p.interp.interp, p.handle, &block,
+		0, 0, C.int(width), C.int(height),
+		C.int(zoomX), C.int(zoomY), C.int(subsampleX), C.int(subsampleY),
+		C.TK_PHOTO_COMPOSITE_SET)
+	if status != C.TCL_OK {
+		return p.interp.GetErrorResult()
+	}
+	return nil
+}

+ 861 - 0
vendor/github.com/visualfc/atk/tk/interp/interp_windows.go

@@ -0,0 +1,861 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package interp
+
+//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -systemdll=false -output zinterp_windows.go interp_windows.go
+
+import (
+	"errors"
+	"fmt"
+	"image"
+	"image/color"
+	"image/draw"
+	"os"
+	"syscall"
+	"unsafe"
+)
+
+//NOTE: BytePtrToString replace cgo C.GoStringN
+
+type Tcl_Interp struct{}
+type Tcl_ThreadId struct{}
+type Tcl_Obj struct{}
+type Tcl_Command struct{}
+type Tk_PhotoHandle struct{}
+
+type Tcl_WideInt int64
+type Tcl_Double float64
+
+type Tcl_Event struct {
+	Proc    uintptr
+	NextPtr *Tcl_Event
+}
+
+type Tk_PhotoImageBlock struct {
+	pixelPtr  *byte
+	width     int32
+	height    int32
+	pitch     int32
+	pixelSize int32
+	offset    [4]int32
+}
+
+// windows api calls
+
+//sys	Tcl_CreateInterp() (interp *Tcl_Interp) = tcl86t.Tcl_CreateInterp
+//sys	Tcl_DeleteInterp(interp *Tcl_Interp) = tcl86t.Tcl_DeleteInterp
+
+//sys	Tcl_Alloc(size uint) (r *Tcl_Event) = tcl86t.Tcl_Alloc
+//sys	Tcl_Eval(interp *Tcl_Interp, script *byte) (r int32) = tcl86t.Tcl_Eval
+//sys	Tcl_EvalEx(interp *Tcl_Interp, script *byte, length int32, flags int32) (r int32) = tcl86t.Tcl_EvalEx
+//sys	Tcl_GetStringResult(interp *Tcl_Interp) (ret *byte) = tcl86t.Tcl_GetStringResult
+//sys	Tcl_GetObjResult(interp *Tcl_Interp) (obj *Tcl_Obj) = tcl86t.Tcl_GetObjResult
+//sys	Tcl_GetWideIntFromObj(interp *Tcl_Interp, obj *Tcl_Obj, out *Tcl_WideInt) (status int32) = tcl86t.Tcl_GetWideIntFromObj
+//-sys	Tcl_GetLongFromObj(interp *Tcl_Interp, obj *Tcl_Obj, out *int) (status int32) = tcl86t.Tcl_GetLongFromObj
+//sys	Tcl_GetDoubleFromObj(interp *Tcl_Interp, obj *Tcl_Obj, out *Tcl_Double) (status int32) = tcl86t.Tcl_GetDoubleFromObj
+//sys	Tcl_GetBooleanFromObj(interp *Tcl_Interp, obj *Tcl_Obj, out *int32) (status int32) = tcl86t.Tcl_GetBooleanFromObj
+//sys	Tcl_GetStringFromObj(obj *Tcl_Obj, length *int32) (ret *byte) = tcl86t.Tcl_GetStringFromObj
+//sys	Tcl_NewWideIntObj(value Tcl_WideInt) (obj *Tcl_Obj) = tcl86t.Tcl_NewWideIntObj
+//-sys	Tcl_NewLongObj(value int) (obj *Tcl_Obj) = tcl86t.Tcl_NewLongObj
+//sys	Tcl_NewDoubleObj(value Tcl_Double) (obj *Tcl_Obj) = tcl86t.Tcl_NewDoubleObj
+//sys	Tcl_NewBooleanObj(value int32) (obj *Tcl_Obj) = tcl86t.Tcl_NewBooleanObj
+//sys	Tcl_NewStringObj(bytes *byte, length int32) (obj *Tcl_Obj) = tcl86t.Tcl_NewStringObj
+//sys	Tcl_Init(interp *Tcl_Interp) (r int32) = tcl86t.Tcl_Init
+//sys	Tcl_GetCurrentThread() (threadid *Tcl_ThreadId) = tcl86t.Tcl_GetCurrentThread
+//sys	Tcl_ThreadQueueEvent(threadId *Tcl_ThreadId, evPtr *Tcl_Event, positon Tcl_QueuePosition) = tcl86t.Tcl_ThreadQueueEvent
+//sys	Tcl_ThreadAlert(threadId *Tcl_ThreadId) = tcl86t.Tcl_ThreadAlert
+//sys	Tcl_CreateObjCommand(interp *Tcl_Interp, cmdName *byte, proc uintptr, clientData uintptr, deleteProc uintptr) (cmd *Tcl_Command) = tcl86t.Tcl_CreateObjCommand
+//sys	Tcl_CreateCommand(interp *Tcl_Interp, cmdName *byte, proc uintptr, clientData uintptr, deleteProc uintptr) (cmd *Tcl_Command) = tcl86t.Tcl_CreateCommand
+//sys	Tcl_SetObjResult(interp *Tcl_Interp, resultObjPtr *Tcl_Obj) = tcl86t.Tcl_SetObjResult
+//sys	Tcl_WrongNumArgs(interp *Tcl_Interp, objc int32, objv uintptr, message *byte) = tcl86t.Tcl_WrongNumArgs
+//sys	Tcl_NewListObj(objc int, objv **Tcl_Obj)(obj *Tcl_Obj) = tcl86t.Tcl_NewListObj
+//sys	Tcl_ListObjLength(interp *Tcl_Interp, listobj *Tcl_Obj, length *int32) (status int32) = tcl86t.Tcl_ListObjLength
+//sys	Tcl_ListObjIndex(interp *Tcl_Interp, listobj *Tcl_Obj, index int32, out **Tcl_Obj) (status int32) = tcl86t.Tcl_ListObjIndex
+//sys	Tcl_ListObjGetElements(interp *Tcl_Interp, listobj *Tcl_Obj, objc *int32, objv ***Tcl_Obj)(status int32) = tcl86t.Tcl_ListObjGetElements
+//sys	Tcl_SetListObj(listobj *Tcl_Obj, objc int, objv **Tcl_Obj) = tcl86t.Tcl_SetListObj
+//sys	Tcl_ListObjAppendElement(interp *Tcl_Interp, listobj *Tcl_Obj, obj *Tcl_Obj) (status int32) = tcl86t.Tcl_ListObjAppendElement
+//sys	Tcl_ListObjReplace(interp *Tcl_Interp, listobj *Tcl_Obj, first int32, count int32, objc int32, objv **Tcl_Obj) (status int32) = tcl86t.Tcl_ListObjReplace
+//sys	Tcl_GetVar2Ex(interp *Tcl_Interp,part1 *byte, part2 *byte, flags int32) (obj *Tcl_Obj) = tcl86t.Tcl_GetVar2Ex
+//sys	Tcl_SetVar(interp *Tcl_Interp,name *byte, value *byte, flags int32) (r *byte) = tcl86t.Tcl_SetVar
+//sys	Tcl_SetVar2Ex(interp *Tcl_Interp,part1 *byte, part2 *byte, value *Tcl_Obj, flags int32) (r *byte) = tcl86t.Tcl_SetVar2Ex
+//sys	Tcl_UnsetVar(interp *Tcl_Interp,part1 *byte, flags int32) (status int32) = tcl86t.Tcl_UnsetVar
+
+//sys	Tk_Init(interp *Tcl_Interp) (r int32) = tk86t.Tk_Init
+//sys	Tk_MainLoop() = tk86t.Tk_MainLoop
+//sys	Tk_FindPhoto(interp *Tcl_Interp, imageName *byte) (handle *Tk_PhotoHandle) = tk86t.Tk_FindPhoto
+//sys	Tk_PhotoBlank(handle *Tk_PhotoHandle) = tk86t.Tk_PhotoBlank
+//sys	Tk_PhotoSetSize(interp *Tcl_Interp,handle *Tk_PhotoHandle, width int32, height int32) (status int32) = tk86t.Tk_PhotoSetSize
+//sys	Tk_PhotoGetSize(hanlde *Tk_PhotoHandle, widthPtr *int32, heightPtr *int32) = tk86t.Tk_PhotoGetSize
+//sys	Tk_PhotoExpand(interp *Tcl_Interp,handle *Tk_PhotoHandle, width int32, height int32) (status int32) = tk86t.Tk_PhotoExpand
+//sys	Tk_PhotoGetImage(handle *Tk_PhotoHandle, blockPtr *Tk_PhotoImageBlock) (status int32) = tk86t.Tk_PhotoGetImage
+//sys	Tk_PhotoPutBlock(interp *Tcl_Interp, handle *Tk_PhotoHandle,blockPtr *Tk_PhotoImageBlock, x int32, y int32, width int32, height int32, compRule int32) (status int32) = tk86t.Tk_PhotoPutBlock
+//sys	Tk_PhotoPutZoomedBlock(interp *Tcl_Interp, handle *Tk_PhotoHandle,blockPtr *Tk_PhotoImageBlock, x int32, y int32, width int32, height int32, zoomX int32, zoomY int32, subsampleX int32, subsampleY int32, compRule int32) (status int32) = tk86t.Tk_PhotoPutZoomedBlock
+
+func init() {
+	err := modtcl86t.Load()
+	if err != nil {
+		modtcl86t.Name = "tcl86.dll"
+		modtk86t.Name = "tk86.dll"
+	}
+}
+
+var (
+	mainLoopThreadId *Tcl_ThreadId
+)
+
+func _go_async_event_handler(ev *Tcl_Event, flags int32) int {
+	if flags != TCL_ALL_EVENTS {
+		return 0
+	}
+	if fn, ok := globalAsyncEvent.Load(unsafe.Pointer(ev)); ok {
+		fn.(func())()
+		globalAsyncEvent.Delete(unsafe.Pointer(ev))
+	}
+	return 1
+}
+
+func IsMainThread() bool {
+	return Tcl_GetCurrentThread() == mainLoopThreadId
+}
+
+func async_send_event(tid *Tcl_ThreadId, fn func()) {
+	var ev *Tcl_Event
+	ev = Tcl_Alloc(uint(unsafe.Sizeof(*ev)))
+	ev.Proc = syscall.NewCallbackCDecl(_go_async_event_handler)
+	ev.NextPtr = nil
+	globalAsyncEvent.Store(unsafe.Pointer(ev), fn)
+	Tcl_ThreadQueueEvent(tid, ev, TCL_QUEUE_TAIL)
+	Tcl_ThreadAlert(tid)
+}
+
+func Async(fn func()) {
+	if fn == nil {
+		return
+	}
+	async_send_event(mainLoopThreadId, fn)
+}
+
+func MainLoop(fn func()) {
+	mainLoopThreadId = Tcl_GetCurrentThread()
+	if fn != nil {
+		fn()
+	}
+	Tk_MainLoop()
+	mainLoopThreadId = nil
+}
+
+type Interp struct {
+	interp      *Tcl_Interp
+	supportTk86 bool
+}
+
+func NewInterp() (*Interp, error) {
+	err := modtcl86t.Load()
+	if err != nil {
+		return nil, err
+	}
+	interp := Tcl_CreateInterp()
+	if interp == nil {
+		return nil, errors.New("Tcl_CreateInterp failed")
+	}
+	return &Interp{interp, false}, nil
+}
+
+func (p *Interp) SupportTk86() bool {
+	return p.supportTk86
+}
+
+func (p *Interp) InitTcl(tcl_library string) error {
+	if tcl_library != "" {
+		p.Eval(fmt.Sprintf("set tcl_library {%s}", tcl_library))
+	}
+	if Tcl_Init(p.interp) != TCL_OK {
+		err := errors.New("Tcl_Init failed")
+		return err
+	}
+	return nil
+}
+
+func (p *Interp) InitTk(tk_library string) error {
+	err := modtk86t.Load()
+	if err != nil {
+		return err
+	}
+	if tk_library != "" {
+		p.Eval(fmt.Sprintf("set tk_library {%s}", tk_library))
+	}
+	if Tk_Init(p.interp) != TCL_OK {
+		err := errors.New("Tk_Init failed")
+		return err
+	}
+	p.supportTk86 = p.TkVersion() >= "8.6"
+	return nil
+}
+
+func (p *Interp) Destroy() error {
+	if p == nil || p.interp == nil {
+		return os.ErrInvalid
+	}
+	Tcl_DeleteInterp(p.interp)
+	p.interp = nil
+	return nil
+}
+
+func BytePtrToString(data *byte, length int32) string {
+	if length == 0 {
+		return ""
+	}
+	p := (*[1 << 30]byte)(unsafe.Pointer(data))[:length]
+	a := make([]byte, length)
+	copy(a, p)
+	return string(a)
+}
+
+func (p *Interp) GetObjResult() *Obj {
+	obj := Tcl_GetObjResult(p.interp)
+	return &Obj{obj, p.interp}
+}
+
+func (p *Interp) GetListObjResult() *ListObj {
+	return &ListObj{Tcl_GetObjResult(p.interp), p.interp}
+}
+
+func (p *Interp) Eval(script string) error {
+	s, err := syscall.BytePtrFromString(script)
+	if err != nil {
+		return err
+	}
+	if Tcl_EvalEx(p.interp, s, int32(len(script)), 0) != TCL_OK {
+		err := errors.New(p.GetStringResult())
+		return err
+	}
+	return nil
+}
+
+//typedef int (Tcl_ObjCmdProc) (ClientData clientData, *Tcl_Interp *interp, int objc, struct *Tcl_Obj *const *objv);
+func _go_tcl_objcmd_proc(clientData uintptr, interp *Tcl_Interp, objc int, objv unsafe.Pointer) int {
+	objs := (*(*[1 << 20]*Tcl_Obj)(objv))[1:objc]
+	var args []string
+	for _, obj := range objs {
+		args = append(args, objToString(interp, obj))
+	}
+	result, err := globalCommandMap.Invoke(clientData, args)
+	if err != nil {
+		cs, _ := syscall.BytePtrFromString(err.Error())
+		Tcl_WrongNumArgs(interp, 1, uintptr(objv), cs)
+		return TCL_ERROR
+	}
+	if result != "" {
+		Tcl_SetObjResult(interp, stringToObj(result))
+	}
+	return TCL_OK
+}
+
+//typedef void (Tcl_CmdDeleteProc) (ClientData clientData);
+func _go_tcl_cmddelete_proc(clientData uintptr) int {
+	globalCommandMap.UnRegister(clientData)
+	return 0
+}
+
+func _go_tcl_action_proc(id uintptr, interp *Tcl_Interp, objc int, objv unsafe.Pointer) int {
+	objs := (*(*[1 << 20]*Tcl_Obj)(objv))[1:objc]
+	var args []string
+	for _, obj := range objs {
+		args = append(args, objToString(interp, obj))
+	}
+	err := globalActionMap.Invoke(id, args)
+	if err != nil {
+		cs, _ := syscall.BytePtrFromString(err.Error())
+		Tcl_WrongNumArgs(interp, 1, uintptr(objv), cs)
+		return TCL_ERROR
+	}
+	return TCL_OK
+}
+
+func _go_tcl_actiono_delete_proc(id uintptr) int {
+	globalActionMap.UnRegister(id)
+	return 0
+}
+
+//Tcl_Command Tcl_CreateObjCommand(*Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc);
+func (p *Interp) CreateCommand(name string, fn func([]string) (string, error)) (uintptr, error) {
+	s, err := syscall.BytePtrFromString(name)
+	if err != nil {
+		return 0, err
+	}
+	id := globalCommandMap.Register(fn)
+	cmd := Tcl_CreateObjCommand(p.interp, s, syscall.NewCallbackCDecl(_go_tcl_objcmd_proc), id, syscall.NewCallbackCDecl(_go_tcl_cmddelete_proc))
+	if cmd == nil {
+		err := fmt.Errorf("CreateCommand %v failed", name)
+		return 0, err
+	}
+	return id, nil
+}
+
+func (p *Interp) InvokeCommand(id uintptr, args []string) (string, error) {
+	return globalCommandMap.Invoke(id, args)
+}
+
+func (p *Interp) CreateAction(name string, action func([]string)) (uintptr, error) {
+	s, err := syscall.BytePtrFromString(name)
+	if err != nil {
+		return 0, err
+	}
+	id := globalActionMap.Register(action)
+	cmd := Tcl_CreateObjCommand(p.interp, s, syscall.NewCallbackCDecl(_go_tcl_action_proc), id, syscall.NewCallbackCDecl(_go_tcl_actiono_delete_proc))
+	if cmd == nil {
+		err := fmt.Errorf("CreateAction %v failed", name)
+		return 0, err
+	}
+	return id, nil
+}
+
+func (p *Interp) InvokeAction(id uintptr, args []string) error {
+	return globalActionMap.Invoke(id, args)
+}
+
+const (
+	TCL_LEAVE_ERR_MSG  = 0x200
+	TCL_GLOBAL_ONLY    = 1
+	TCL_NAMESPACE_ONLY = 2
+	TCL_APPEND_VALUE   = 4
+	TCL_LIST_ELEMENT   = 8
+)
+
+func (p *Interp) GetVar(name string, global bool) *Obj {
+	cname, err := syscall.BytePtrFromString(name)
+	if err != nil {
+		return nil
+	}
+	var flag int32 = TCL_LEAVE_ERR_MSG
+	if global {
+		flag |= TCL_GLOBAL_ONLY
+	}
+	obj := Tcl_GetVar2Ex(p.interp, cname, nil, flag)
+	if obj == nil {
+		return nil
+	}
+	return &Obj{obj, p.interp}
+}
+
+func (p *Interp) GetList(name string, global bool) *ListObj {
+	return (*ListObj)(p.GetVar(name, global))
+}
+
+func (p *Interp) SetStringList(name string, list []string, global bool) error {
+	obj := NewListObj(p)
+	obj.AppendStringList(list)
+	return p.SetVarObj(name, (*Obj)(obj), global)
+}
+
+func (p *Interp) AppendStringListList(name string, list []string, global bool) error {
+	cname, err := syscall.BytePtrFromString(name)
+	if err != nil {
+		return err
+	}
+	var flag int32 = TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE | TCL_LIST_ELEMENT
+	if global {
+		flag |= TCL_GLOBAL_ONLY
+	}
+	for _, value := range list {
+		cvalue, _ := syscall.BytePtrFromString(value)
+		Tcl_SetVar(p.interp, cname, cvalue, flag)
+	}
+	return nil
+}
+
+func (p *Interp) AppendStringList(name string, value string, global bool) error {
+	cname, err := syscall.BytePtrFromString(name)
+	if err != nil {
+		return err
+	}
+	cvalue, err := syscall.BytePtrFromString(value)
+	if err != nil {
+		return err
+	}
+	var flag int32 = TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE | TCL_LIST_ELEMENT
+	if global {
+		flag |= TCL_GLOBAL_ONLY
+	}
+	r := Tcl_SetVar(p.interp, cname, cvalue, flag)
+	if r == nil {
+		return p.GetErrorResult()
+	}
+	return nil
+}
+
+func (p *Interp) SetVarObj(name string, obj *Obj, global bool) error {
+	if obj == nil {
+		return os.ErrInvalid
+	}
+	cname, err := syscall.BytePtrFromString(name)
+	if err != nil {
+		return err
+	}
+	var flag int32 = TCL_LEAVE_ERR_MSG
+	if global {
+		flag |= TCL_GLOBAL_ONLY
+	}
+	r := Tcl_SetVar2Ex(p.interp, cname, nil, obj.obj, flag)
+	if r == nil {
+		return p.GetErrorResult()
+	}
+	return nil
+}
+
+func (p *Interp) SetVarListObj(name string, obj *ListObj, global bool) error {
+	return p.SetVarObj(name, (*Obj)(obj), global)
+}
+
+func (p *Interp) SetStringVar(name string, value string, global bool) error {
+	cname, err := syscall.BytePtrFromString(name)
+	if err != nil {
+		return err
+	}
+	cvalue, err := syscall.BytePtrFromString(value)
+	if err != nil {
+		return err
+	}
+	var flag int32 = TCL_LEAVE_ERR_MSG
+	if global {
+		flag |= TCL_GLOBAL_ONLY
+	}
+	r := Tcl_SetVar(p.interp, cname, cvalue, flag)
+	if r == nil {
+		return p.GetErrorResult()
+	}
+	return nil
+}
+
+func (p *Interp) AppendStringVar(name string, value string, global bool) error {
+	cname, err := syscall.BytePtrFromString(name)
+	if err != nil {
+		return err
+	}
+	cvalue, err := syscall.BytePtrFromString(value)
+	if err != nil {
+		return err
+	}
+	var flag int32 = TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
+	if global {
+		flag |= TCL_GLOBAL_ONLY
+	}
+	r := Tcl_SetVar(p.interp, cname, cvalue, flag)
+	if r == nil {
+		return p.GetErrorResult()
+	}
+	return nil
+}
+
+func (p *Interp) UnsetVar(name string, global bool) error {
+	cname, err := syscall.BytePtrFromString(name)
+	if err != nil {
+		return err
+	}
+	var flag int32 = TCL_LEAVE_ERR_MSG
+	if global {
+		flag |= TCL_GLOBAL_ONLY
+	}
+	r := Tcl_UnsetVar(p.interp, cname, flag)
+	if r != TCL_OK {
+		return p.GetErrorResult()
+	}
+	return nil
+}
+
+type Obj struct {
+	obj    *Tcl_Obj
+	interp *Tcl_Interp
+}
+
+func NewRawObj(obj *Tcl_Obj, interp *Tcl_Interp) *Obj {
+	return &Obj{obj, interp}
+}
+
+func (o *Obj) ToFloat64() float64 {
+	var out Tcl_Double
+	status := Tcl_GetDoubleFromObj(o.interp, o.obj, &out)
+	if status == TCL_OK {
+		return float64(out)
+	}
+	return 0
+}
+
+func (o *Obj) ToInt64() int64 {
+	var out Tcl_WideInt
+	status := Tcl_GetWideIntFromObj(o.interp, o.obj, &out)
+	if status == TCL_OK {
+		return int64(out)
+	}
+	return 0
+}
+
+func (o *Obj) ToInt() int {
+	return int(o.ToInt64())
+}
+
+func (o *Obj) ToUint() uint {
+	return uint(o.ToInt64())
+}
+
+func (o *Obj) ToBool() bool {
+	var out int32
+	status := Tcl_GetBooleanFromObj(o.interp, o.obj, &out)
+	if status == TCL_OK {
+		return out == 1
+	}
+	return false
+}
+
+func (o *Obj) ToString() string {
+	var n int32
+	out := Tcl_GetStringFromObj(o.obj, &n)
+	return BytePtrToString(out, n)
+}
+
+func NewStringObj(value string, p *Interp) *Obj {
+	s, err := syscall.BytePtrFromString(value)
+	if err != nil {
+		return nil
+	}
+	return &Obj{Tcl_NewStringObj(s, int32(len(value))), p.interp}
+}
+
+//NOTE: Tcl_NewDoubleObj test error on windows
+func NewFloat64Obj(value float64, p *Interp) *Obj {
+	//return &Obj{Tcl_NewDoubleObj(Tcl_Double(value)), p.interp}
+	return NewStringObj(fmt.Sprintf("%v", value), p)
+}
+
+//NOTE: Tcl_NewWideIntObj test error on windows 32 bit
+func NewInt64Obj(value int64, p *Interp) *Obj {
+	return NewStringObj(fmt.Sprintf("%v", value), p)
+	//return &Obj{Tcl_NewWideIntObj(Tcl_WideInt(value)), p.interp}
+}
+
+//NOTE: use int to string for amd64/i386
+func NewIntObj(value int, p *Interp) *Obj {
+	return NewStringObj(fmt.Sprintf("%v", value), p)
+	//	return &Obj{Tcl_NewLongObj(value), p.interp}
+}
+
+func NewBoolObj(value bool, p *Interp) *Obj {
+	if value {
+		return &Obj{Tcl_NewBooleanObj(1), p.interp}
+	} else {
+		return &Obj{Tcl_NewBooleanObj(0), p.interp}
+	}
+}
+
+func objToString(interp *Tcl_Interp, obj *Tcl_Obj) string {
+	var n int32
+	out := Tcl_GetStringFromObj(obj, &n)
+	return BytePtrToString(out, n)
+	//return C.GoStringN((*C.char)(unsafe.Pointer(out)), (C.int)(n))
+}
+
+func stringToObj(value string) *Tcl_Obj {
+	s, err := syscall.BytePtrFromString(value)
+	if err != nil {
+		return nil
+	}
+	return Tcl_NewStringObj(s, int32(len(value)))
+}
+
+type ListObj Obj
+
+func NewListObj(p *Interp) *ListObj {
+	o := Tcl_NewListObj(0, nil)
+	return &ListObj{o, p.interp}
+}
+
+func (o *ListObj) Length() int {
+	var length int32
+	Tcl_ListObjLength(o.interp, o.obj, &length)
+	return int(length)
+}
+
+func (o *ListObj) IndexObj(index int) *Obj {
+	var obj *Tcl_Obj
+	r := Tcl_ListObjIndex(o.interp, o.obj, int32(index), &obj)
+	if r != TCL_OK || obj == nil {
+		return nil
+	}
+	return &Obj{obj, o.interp}
+}
+
+func (o *ListObj) IndexString(index int) string {
+	var obj *Tcl_Obj
+	r := Tcl_ListObjIndex(o.interp, o.obj, int32(index), &obj)
+	if r != TCL_OK || obj == nil {
+		return ""
+	}
+	return objToString(o.interp, obj)
+}
+
+func (o *ListObj) ToObjList() (list []*Obj) {
+	var objs **Tcl_Obj
+	var objnum int32
+	Tcl_ListObjGetElements(o.interp, o.obj, &objnum, &objs)
+	if objnum == 0 {
+		return
+	}
+	lst := (*[1 << 20]*Tcl_Obj)(unsafe.Pointer(objs))[:int(objnum):int(objnum)]
+	for _, v := range lst {
+		list = append(list, &Obj{v, o.interp})
+	}
+	return
+}
+
+func (o *ListObj) ToStringList() (list []string) {
+	var objs **Tcl_Obj
+	var objnum int32
+	Tcl_ListObjGetElements(o.interp, o.obj, &objnum, &objs)
+	if objnum == 0 {
+		return
+	}
+	lst := (*[1 << 20]*Tcl_Obj)(unsafe.Pointer(objs))[:int(objnum):int(objnum)]
+	var n int32
+	for _, obj := range lst {
+		out := Tcl_GetStringFromObj(obj, &n)
+		list = append(list, BytePtrToString(out, n))
+	}
+	return
+}
+
+func (o *ListObj) ToIntList() (list []int) {
+	var objs **Tcl_Obj
+	var objnum int32
+	Tcl_ListObjGetElements(o.interp, o.obj, &objnum, &objs)
+	if objnum == 0 {
+		return
+	}
+	lst := (*[1 << 20]*Tcl_Obj)(unsafe.Pointer(objs))[:int(objnum):int(objnum)]
+	var out Tcl_WideInt
+	for _, obj := range lst {
+		Tcl_GetWideIntFromObj(o.interp, obj, &out)
+		list = append(list, int(out))
+	}
+	return
+}
+
+func (o *ListObj) SetStringList(list []string) {
+	Tcl_SetListObj(o.obj, 0, nil)
+	o.AppendStringList(list)
+}
+
+func (o *ListObj) AppendStringList(list []string) {
+	for _, v := range list {
+		cs, _ := syscall.BytePtrFromString(v)
+		obj := Tcl_NewStringObj(cs, int32(len(v)))
+		Tcl_ListObjAppendElement(o.interp, o.obj, obj)
+	}
+}
+
+func (o *ListObj) AppendObj(obj *Obj) bool {
+	if obj == nil {
+		return false
+	}
+	Tcl_ListObjAppendElement(o.interp, o.obj, obj.obj)
+	return true
+}
+
+func (o *ListObj) AppendString(s string) {
+	Tcl_ListObjAppendElement(o.interp, o.obj, stringToObj(s))
+}
+
+func (o *ListObj) InsertObj(index int, obj *Obj) {
+	Tcl_ListObjReplace(o.interp, o.obj, int32(index), 0, 1, &obj.obj)
+}
+
+func (o *ListObj) InsertString(index int, s string) {
+	obj := stringToObj(s)
+	Tcl_ListObjReplace(o.interp, o.obj, int32(index), 0, 1, &obj)
+}
+
+func (o *ListObj) SetIndexObj(index int, obj *Obj) bool {
+	if obj == nil {
+		return false
+	}
+	Tcl_ListObjReplace(o.interp, o.obj, int32(index), 1, 1, &obj.obj)
+	return true
+}
+
+func (o *ListObj) SetIndexString(index int, s string) {
+	obj := stringToObj(s)
+	Tcl_ListObjReplace(o.interp, o.obj, int32(index), 1, 1, &obj)
+}
+
+func (o *ListObj) Remove(first int, count int) {
+	Tcl_ListObjReplace(o.interp, o.obj, int32(first), int32(count), 0, nil)
+}
+
+type Photo struct {
+	handle *Tk_PhotoHandle
+	interp *Interp
+}
+
+func FindPhoto(interp *Interp, imageName string) *Photo {
+	cs, err := syscall.BytePtrFromString(imageName)
+	if err != nil {
+		return nil
+	}
+	handle := Tk_FindPhoto(interp.interp, cs)
+	if handle == nil {
+		return nil
+	}
+	return &Photo{handle, interp}
+}
+
+func (p *Photo) Blank() {
+	Tk_PhotoBlank(p.handle)
+}
+
+func (p *Photo) SetSize(width int, height int) error {
+	status := Tk_PhotoSetSize(p.interp.interp, p.handle, int32(width), int32(height))
+	if status != TCL_OK {
+		return p.interp.GetErrorResult()
+	}
+	return nil
+}
+
+func (p *Photo) Size() (int, int) {
+	var width, height int32
+	Tk_PhotoGetSize(p.handle, &width, &height)
+	return int(width), int(height)
+}
+
+func (p *Photo) Expand(width int, height int) error {
+	status := Tk_PhotoExpand(p.interp.interp, p.handle, int32(width), int32(height))
+	if status != TCL_OK {
+		return p.interp.GetErrorResult()
+	}
+	return nil
+}
+
+func (p *Photo) ToImage() image.Image {
+	var block Tk_PhotoImageBlock
+	Tk_PhotoGetImage(p.handle, &block)
+	if block.width == 0 || block.height == 0 {
+		return nil
+	}
+	r := image.Rect(0, 0, int(block.width), int(block.height))
+	//pix := GoBytes(unsafe.Pointer(block.pixelPtr), int(4*block.width*block.height))
+	//pix := make([]uint8
+	img := image.NewNRGBA(r)
+	data := (*([1 << 20]byte))(unsafe.Pointer(block.pixelPtr))[:4*block.width*block.height]
+	copy(img.Pix, data)
+	return img
+}
+
+const (
+	TK_PHOTO_COMPOSITE_OVERLAY = 0
+	TK_PHOTO_COMPOSITE_SET     = 1
+)
+
+func (p *Photo) PutImage(img image.Image, tk85alphacolor color.Color) error {
+	if img == nil || img.Bounds().Empty() {
+		return os.ErrInvalid
+	}
+	width := img.Bounds().Dx()
+	height := img.Bounds().Dy()
+	var block Tk_PhotoImageBlock
+	if p.interp.supportTk86 {
+		dstImage, ok := img.(*image.NRGBA)
+		if !ok {
+			dstImage = image.NewNRGBA(img.Bounds())
+			draw.Draw(dstImage, dstImage.Bounds(), img, img.Bounds().Min, draw.Src)
+		}
+		block = Tk_PhotoImageBlock{
+			&dstImage.Pix[0],
+			int32(width),
+			int32(height),
+			int32(dstImage.Stride),
+			4,
+			[...]int32{0, 1, 2, 3},
+		}
+	} else {
+		var r, g, b uint8
+		if tk85alphacolor != nil {
+			clr := color.RGBAModel.Convert(tk85alphacolor).(color.RGBA)
+			r, g, b = clr.R, clr.G, clr.B
+		}
+		dstImage := image.NewRGBA(img.Bounds())
+		for i := 0; i < len(dstImage.Pix); i += 4 {
+			dstImage.Pix[i+0] = r
+			dstImage.Pix[i+1] = g
+			dstImage.Pix[i+2] = b
+			dstImage.Pix[i+3] = 0xff
+		}
+		draw.Draw(dstImage, dstImage.Bounds(), img, img.Bounds().Min, draw.Over)
+		block = Tk_PhotoImageBlock{
+			&dstImage.Pix[0],
+			int32(width),
+			int32(height),
+			int32(dstImage.Stride),
+			4,
+			[...]int32{0, 1, 2, 3},
+		}
+	}
+	status := Tk_PhotoPutBlock(p.interp.interp, p.handle, &block, 0, 0,
+		int32(img.Bounds().Dx()), int32(img.Bounds().Dy()),
+		TK_PHOTO_COMPOSITE_SET)
+	if status != TCL_OK {
+		return p.interp.GetErrorResult()
+	}
+	return nil
+}
+
+func (p *Photo) PutZoomedImage(img image.Image, zoomX, zoomY, subsampleX, subsampleY int, tk85alphacolor color.Color) error {
+	if img == nil || img.Bounds().Empty() {
+		return os.ErrInvalid
+	}
+	width := img.Bounds().Dx()
+	height := img.Bounds().Dy()
+	var block Tk_PhotoImageBlock
+	if p.interp.supportTk86 {
+		dstImage, ok := img.(*image.NRGBA)
+		if !ok {
+			dstImage = image.NewNRGBA(img.Bounds())
+			draw.Draw(dstImage, dstImage.Bounds(), img, img.Bounds().Min, draw.Src)
+		}
+		block = Tk_PhotoImageBlock{
+			&dstImage.Pix[0],
+			int32(width),
+			int32(height),
+			int32(dstImage.Stride),
+			4,
+			[...]int32{0, 1, 2, 3},
+		}
+	} else {
+		var r, g, b uint8
+		if tk85alphacolor != nil {
+			clr := color.RGBAModel.Convert(tk85alphacolor).(color.RGBA)
+			r, g, b = clr.R, clr.G, clr.B
+		}
+		dstImage := image.NewRGBA(img.Bounds())
+		for i := 0; i < len(dstImage.Pix); i += 4 {
+			dstImage.Pix[i+0] = r
+			dstImage.Pix[i+1] = g
+			dstImage.Pix[i+2] = b
+			dstImage.Pix[i+3] = 0xff
+		}
+		draw.Draw(dstImage, dstImage.Bounds(), img, img.Bounds().Min, draw.Over)
+		block = Tk_PhotoImageBlock{
+			&dstImage.Pix[0],
+			int32(width),
+			int32(height),
+			int32(dstImage.Stride),
+			4,
+			[...]int32{0, 1, 2, 3},
+		}
+	}
+	status := Tk_PhotoPutZoomedBlock(p.interp.interp, p.handle, &block,
+		0, 0, int32(width), int32(height),
+		int32(zoomX), int32(zoomY), int32(subsampleX), int32(subsampleY),
+		TK_PHOTO_COMPOSITE_SET)
+	if status != TCL_OK {
+		return p.interp.GetErrorResult()
+	}
+	return nil
+}

+ 13 - 0
vendor/github.com/visualfc/atk/tk/interp/syncmap.go

@@ -0,0 +1,13 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+// +build go1.9
+
+package interp
+
+import (
+	"sync"
+)
+
+var (
+	globalAsyncEvent sync.Map
+)

+ 13 - 0
vendor/github.com/visualfc/atk/tk/interp/syncmap_18.go

@@ -0,0 +1,13 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+// +build !go1.9
+
+package interp
+
+import (
+	"golang.org/x/sync/syncmap"
+)
+
+var (
+	globalAsyncEvent syncmap.Map
+)

+ 340 - 0
vendor/github.com/visualfc/atk/tk/interp/zinterp_windows.go

@@ -0,0 +1,340 @@
+// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
+
+package interp
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+var _ unsafe.Pointer
+
+// Do the interface allocations only once for common
+// Errno values.
+const (
+	errnoERROR_IO_PENDING = 997
+)
+
+var (
+	errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
+)
+
+// errnoErr returns common boxed Errno values, to prevent
+// allocations at runtime.
+func errnoErr(e syscall.Errno) error {
+	switch e {
+	case 0:
+		return nil
+	case errnoERROR_IO_PENDING:
+		return errERROR_IO_PENDING
+	}
+	// TODO: add more here, after collecting data on the common
+	// error values see on Windows. (perhaps when running
+	// all.bat?)
+	return e
+}
+
+var (
+	modtcl86t = syscall.NewLazyDLL("tcl86t.dll")
+	modtk86t  = syscall.NewLazyDLL("tk86t.dll")
+
+	procTcl_CreateInterp         = modtcl86t.NewProc("Tcl_CreateInterp")
+	procTcl_DeleteInterp         = modtcl86t.NewProc("Tcl_DeleteInterp")
+	procTcl_Alloc                = modtcl86t.NewProc("Tcl_Alloc")
+	procTcl_Eval                 = modtcl86t.NewProc("Tcl_Eval")
+	procTcl_EvalEx               = modtcl86t.NewProc("Tcl_EvalEx")
+	procTcl_GetStringResult      = modtcl86t.NewProc("Tcl_GetStringResult")
+	procTcl_GetObjResult         = modtcl86t.NewProc("Tcl_GetObjResult")
+	procTcl_GetWideIntFromObj    = modtcl86t.NewProc("Tcl_GetWideIntFromObj")
+	procTcl_GetDoubleFromObj     = modtcl86t.NewProc("Tcl_GetDoubleFromObj")
+	procTcl_GetBooleanFromObj    = modtcl86t.NewProc("Tcl_GetBooleanFromObj")
+	procTcl_GetStringFromObj     = modtcl86t.NewProc("Tcl_GetStringFromObj")
+	procTcl_NewWideIntObj        = modtcl86t.NewProc("Tcl_NewWideIntObj")
+	procTcl_NewDoubleObj         = modtcl86t.NewProc("Tcl_NewDoubleObj")
+	procTcl_NewBooleanObj        = modtcl86t.NewProc("Tcl_NewBooleanObj")
+	procTcl_NewStringObj         = modtcl86t.NewProc("Tcl_NewStringObj")
+	procTcl_Init                 = modtcl86t.NewProc("Tcl_Init")
+	procTcl_GetCurrentThread     = modtcl86t.NewProc("Tcl_GetCurrentThread")
+	procTcl_ThreadQueueEvent     = modtcl86t.NewProc("Tcl_ThreadQueueEvent")
+	procTcl_ThreadAlert          = modtcl86t.NewProc("Tcl_ThreadAlert")
+	procTcl_CreateObjCommand     = modtcl86t.NewProc("Tcl_CreateObjCommand")
+	procTcl_CreateCommand        = modtcl86t.NewProc("Tcl_CreateCommand")
+	procTcl_SetObjResult         = modtcl86t.NewProc("Tcl_SetObjResult")
+	procTcl_WrongNumArgs         = modtcl86t.NewProc("Tcl_WrongNumArgs")
+	procTcl_NewListObj           = modtcl86t.NewProc("Tcl_NewListObj")
+	procTcl_ListObjLength        = modtcl86t.NewProc("Tcl_ListObjLength")
+	procTcl_ListObjIndex         = modtcl86t.NewProc("Tcl_ListObjIndex")
+	procTcl_ListObjGetElements   = modtcl86t.NewProc("Tcl_ListObjGetElements")
+	procTcl_SetListObj           = modtcl86t.NewProc("Tcl_SetListObj")
+	procTcl_ListObjAppendElement = modtcl86t.NewProc("Tcl_ListObjAppendElement")
+	procTcl_ListObjReplace       = modtcl86t.NewProc("Tcl_ListObjReplace")
+	procTcl_GetVar2Ex            = modtcl86t.NewProc("Tcl_GetVar2Ex")
+	procTcl_SetVar               = modtcl86t.NewProc("Tcl_SetVar")
+	procTcl_SetVar2Ex            = modtcl86t.NewProc("Tcl_SetVar2Ex")
+	procTcl_UnsetVar             = modtcl86t.NewProc("Tcl_UnsetVar")
+	procTk_Init                  = modtk86t.NewProc("Tk_Init")
+	procTk_MainLoop              = modtk86t.NewProc("Tk_MainLoop")
+	procTk_FindPhoto             = modtk86t.NewProc("Tk_FindPhoto")
+	procTk_PhotoBlank            = modtk86t.NewProc("Tk_PhotoBlank")
+	procTk_PhotoSetSize          = modtk86t.NewProc("Tk_PhotoSetSize")
+	procTk_PhotoGetSize          = modtk86t.NewProc("Tk_PhotoGetSize")
+	procTk_PhotoExpand           = modtk86t.NewProc("Tk_PhotoExpand")
+	procTk_PhotoGetImage         = modtk86t.NewProc("Tk_PhotoGetImage")
+	procTk_PhotoPutBlock         = modtk86t.NewProc("Tk_PhotoPutBlock")
+	procTk_PhotoPutZoomedBlock   = modtk86t.NewProc("Tk_PhotoPutZoomedBlock")
+)
+
+func Tcl_CreateInterp() (interp *Tcl_Interp) {
+	r0, _, _ := syscall.Syscall(procTcl_CreateInterp.Addr(), 0, 0, 0, 0)
+	interp = (*Tcl_Interp)(unsafe.Pointer(r0))
+	return
+}
+
+func Tcl_DeleteInterp(interp *Tcl_Interp) {
+	syscall.Syscall(procTcl_DeleteInterp.Addr(), 1, uintptr(unsafe.Pointer(interp)), 0, 0)
+	return
+}
+
+func Tcl_Alloc(size uint) (r *Tcl_Event) {
+	r0, _, _ := syscall.Syscall(procTcl_Alloc.Addr(), 1, uintptr(size), 0, 0)
+	r = (*Tcl_Event)(unsafe.Pointer(r0))
+	return
+}
+
+func Tcl_Eval(interp *Tcl_Interp, script *byte) (r int32) {
+	r0, _, _ := syscall.Syscall(procTcl_Eval.Addr(), 2, uintptr(unsafe.Pointer(interp)), uintptr(unsafe.Pointer(script)), 0)
+	r = int32(r0)
+	return
+}
+
+func Tcl_EvalEx(interp *Tcl_Interp, script *byte, length int32, flags int32) (r int32) {
+	r0, _, _ := syscall.Syscall6(procTcl_EvalEx.Addr(), 4, uintptr(unsafe.Pointer(interp)), uintptr(unsafe.Pointer(script)), uintptr(length), uintptr(flags), 0, 0)
+	r = int32(r0)
+	return
+}
+
+func Tcl_GetStringResult(interp *Tcl_Interp) (ret *byte) {
+	r0, _, _ := syscall.Syscall(procTcl_GetStringResult.Addr(), 1, uintptr(unsafe.Pointer(interp)), 0, 0)
+	ret = (*byte)(unsafe.Pointer(r0))
+	return
+}
+
+func Tcl_GetObjResult(interp *Tcl_Interp) (obj *Tcl_Obj) {
+	r0, _, _ := syscall.Syscall(procTcl_GetObjResult.Addr(), 1, uintptr(unsafe.Pointer(interp)), 0, 0)
+	obj = (*Tcl_Obj)(unsafe.Pointer(r0))
+	return
+}
+
+func Tcl_GetWideIntFromObj(interp *Tcl_Interp, obj *Tcl_Obj, out *Tcl_WideInt) (status int32) {
+	r0, _, _ := syscall.Syscall(procTcl_GetWideIntFromObj.Addr(), 3, uintptr(unsafe.Pointer(interp)), uintptr(unsafe.Pointer(obj)), uintptr(unsafe.Pointer(out)))
+	status = int32(r0)
+	return
+}
+
+func Tcl_GetDoubleFromObj(interp *Tcl_Interp, obj *Tcl_Obj, out *Tcl_Double) (status int32) {
+	r0, _, _ := syscall.Syscall(procTcl_GetDoubleFromObj.Addr(), 3, uintptr(unsafe.Pointer(interp)), uintptr(unsafe.Pointer(obj)), uintptr(unsafe.Pointer(out)))
+	status = int32(r0)
+	return
+}
+
+func Tcl_GetBooleanFromObj(interp *Tcl_Interp, obj *Tcl_Obj, out *int32) (status int32) {
+	r0, _, _ := syscall.Syscall(procTcl_GetBooleanFromObj.Addr(), 3, uintptr(unsafe.Pointer(interp)), uintptr(unsafe.Pointer(obj)), uintptr(unsafe.Pointer(out)))
+	status = int32(r0)
+	return
+}
+
+func Tcl_GetStringFromObj(obj *Tcl_Obj, length *int32) (ret *byte) {
+	r0, _, _ := syscall.Syscall(procTcl_GetStringFromObj.Addr(), 2, uintptr(unsafe.Pointer(obj)), uintptr(unsafe.Pointer(length)), 0)
+	ret = (*byte)(unsafe.Pointer(r0))
+	return
+}
+
+func Tcl_NewWideIntObj(value Tcl_WideInt) (obj *Tcl_Obj) {
+	r0, _, _ := syscall.Syscall(procTcl_NewWideIntObj.Addr(), 1, uintptr(value), 0, 0)
+	obj = (*Tcl_Obj)(unsafe.Pointer(r0))
+	return
+}
+
+func Tcl_NewDoubleObj(value Tcl_Double) (obj *Tcl_Obj) {
+	r0, _, _ := syscall.Syscall(procTcl_NewDoubleObj.Addr(), 1, uintptr(value), 0, 0)
+	obj = (*Tcl_Obj)(unsafe.Pointer(r0))
+	return
+}
+
+func Tcl_NewBooleanObj(value int32) (obj *Tcl_Obj) {
+	r0, _, _ := syscall.Syscall(procTcl_NewBooleanObj.Addr(), 1, uintptr(value), 0, 0)
+	obj = (*Tcl_Obj)(unsafe.Pointer(r0))
+	return
+}
+
+func Tcl_NewStringObj(bytes *byte, length int32) (obj *Tcl_Obj) {
+	r0, _, _ := syscall.Syscall(procTcl_NewStringObj.Addr(), 2, uintptr(unsafe.Pointer(bytes)), uintptr(length), 0)
+	obj = (*Tcl_Obj)(unsafe.Pointer(r0))
+	return
+}
+
+func Tcl_Init(interp *Tcl_Interp) (r int32) {
+	r0, _, _ := syscall.Syscall(procTcl_Init.Addr(), 1, uintptr(unsafe.Pointer(interp)), 0, 0)
+	r = int32(r0)
+	return
+}
+
+func Tcl_GetCurrentThread() (threadid *Tcl_ThreadId) {
+	r0, _, _ := syscall.Syscall(procTcl_GetCurrentThread.Addr(), 0, 0, 0, 0)
+	threadid = (*Tcl_ThreadId)(unsafe.Pointer(r0))
+	return
+}
+
+func Tcl_ThreadQueueEvent(threadId *Tcl_ThreadId, evPtr *Tcl_Event, positon Tcl_QueuePosition) {
+	syscall.Syscall(procTcl_ThreadQueueEvent.Addr(), 3, uintptr(unsafe.Pointer(threadId)), uintptr(unsafe.Pointer(evPtr)), uintptr(positon))
+	return
+}
+
+func Tcl_ThreadAlert(threadId *Tcl_ThreadId) {
+	syscall.Syscall(procTcl_ThreadAlert.Addr(), 1, uintptr(unsafe.Pointer(threadId)), 0, 0)
+	return
+}
+
+func Tcl_CreateObjCommand(interp *Tcl_Interp, cmdName *byte, proc uintptr, clientData uintptr, deleteProc uintptr) (cmd *Tcl_Command) {
+	r0, _, _ := syscall.Syscall6(procTcl_CreateObjCommand.Addr(), 5, uintptr(unsafe.Pointer(interp)), uintptr(unsafe.Pointer(cmdName)), uintptr(proc), uintptr(clientData), uintptr(deleteProc), 0)
+	cmd = (*Tcl_Command)(unsafe.Pointer(r0))
+	return
+}
+
+func Tcl_CreateCommand(interp *Tcl_Interp, cmdName *byte, proc uintptr, clientData uintptr, deleteProc uintptr) (cmd *Tcl_Command) {
+	r0, _, _ := syscall.Syscall6(procTcl_CreateCommand.Addr(), 5, uintptr(unsafe.Pointer(interp)), uintptr(unsafe.Pointer(cmdName)), uintptr(proc), uintptr(clientData), uintptr(deleteProc), 0)
+	cmd = (*Tcl_Command)(unsafe.Pointer(r0))
+	return
+}
+
+func Tcl_SetObjResult(interp *Tcl_Interp, resultObjPtr *Tcl_Obj) {
+	syscall.Syscall(procTcl_SetObjResult.Addr(), 2, uintptr(unsafe.Pointer(interp)), uintptr(unsafe.Pointer(resultObjPtr)), 0)
+	return
+}
+
+func Tcl_WrongNumArgs(interp *Tcl_Interp, objc int32, objv uintptr, message *byte) {
+	syscall.Syscall6(procTcl_WrongNumArgs.Addr(), 4, uintptr(unsafe.Pointer(interp)), uintptr(objc), uintptr(objv), uintptr(unsafe.Pointer(message)), 0, 0)
+	return
+}
+
+func Tcl_NewListObj(objc int, objv **Tcl_Obj) (obj *Tcl_Obj) {
+	r0, _, _ := syscall.Syscall(procTcl_NewListObj.Addr(), 2, uintptr(objc), uintptr(unsafe.Pointer(objv)), 0)
+	obj = (*Tcl_Obj)(unsafe.Pointer(r0))
+	return
+}
+
+func Tcl_ListObjLength(interp *Tcl_Interp, listobj *Tcl_Obj, length *int32) (status int32) {
+	r0, _, _ := syscall.Syscall(procTcl_ListObjLength.Addr(), 3, uintptr(unsafe.Pointer(interp)), uintptr(unsafe.Pointer(listobj)), uintptr(unsafe.Pointer(length)))
+	status = int32(r0)
+	return
+}
+
+func Tcl_ListObjIndex(interp *Tcl_Interp, listobj *Tcl_Obj, index int32, out **Tcl_Obj) (status int32) {
+	r0, _, _ := syscall.Syscall6(procTcl_ListObjIndex.Addr(), 4, uintptr(unsafe.Pointer(interp)), uintptr(unsafe.Pointer(listobj)), uintptr(index), uintptr(unsafe.Pointer(out)), 0, 0)
+	status = int32(r0)
+	return
+}
+
+func Tcl_ListObjGetElements(interp *Tcl_Interp, listobj *Tcl_Obj, objc *int32, objv ***Tcl_Obj) (status int32) {
+	r0, _, _ := syscall.Syscall6(procTcl_ListObjGetElements.Addr(), 4, uintptr(unsafe.Pointer(interp)), uintptr(unsafe.Pointer(listobj)), uintptr(unsafe.Pointer(objc)), uintptr(unsafe.Pointer(objv)), 0, 0)
+	status = int32(r0)
+	return
+}
+
+func Tcl_SetListObj(listobj *Tcl_Obj, objc int, objv **Tcl_Obj) {
+	syscall.Syscall(procTcl_SetListObj.Addr(), 3, uintptr(unsafe.Pointer(listobj)), uintptr(objc), uintptr(unsafe.Pointer(objv)))
+	return
+}
+
+func Tcl_ListObjAppendElement(interp *Tcl_Interp, listobj *Tcl_Obj, obj *Tcl_Obj) (status int32) {
+	r0, _, _ := syscall.Syscall(procTcl_ListObjAppendElement.Addr(), 3, uintptr(unsafe.Pointer(interp)), uintptr(unsafe.Pointer(listobj)), uintptr(unsafe.Pointer(obj)))
+	status = int32(r0)
+	return
+}
+
+func Tcl_ListObjReplace(interp *Tcl_Interp, listobj *Tcl_Obj, first int32, count int32, objc int32, objv **Tcl_Obj) (status int32) {
+	r0, _, _ := syscall.Syscall6(procTcl_ListObjReplace.Addr(), 6, uintptr(unsafe.Pointer(interp)), uintptr(unsafe.Pointer(listobj)), uintptr(first), uintptr(count), uintptr(objc), uintptr(unsafe.Pointer(objv)))
+	status = int32(r0)
+	return
+}
+
+func Tcl_GetVar2Ex(interp *Tcl_Interp, part1 *byte, part2 *byte, flags int32) (obj *Tcl_Obj) {
+	r0, _, _ := syscall.Syscall6(procTcl_GetVar2Ex.Addr(), 4, uintptr(unsafe.Pointer(interp)), uintptr(unsafe.Pointer(part1)), uintptr(unsafe.Pointer(part2)), uintptr(flags), 0, 0)
+	obj = (*Tcl_Obj)(unsafe.Pointer(r0))
+	return
+}
+
+func Tcl_SetVar(interp *Tcl_Interp, name *byte, value *byte, flags int32) (r *byte) {
+	r0, _, _ := syscall.Syscall6(procTcl_SetVar.Addr(), 4, uintptr(unsafe.Pointer(interp)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), uintptr(flags), 0, 0)
+	r = (*byte)(unsafe.Pointer(r0))
+	return
+}
+
+func Tcl_SetVar2Ex(interp *Tcl_Interp, part1 *byte, part2 *byte, value *Tcl_Obj, flags int32) (r *byte) {
+	r0, _, _ := syscall.Syscall6(procTcl_SetVar2Ex.Addr(), 5, uintptr(unsafe.Pointer(interp)), uintptr(unsafe.Pointer(part1)), uintptr(unsafe.Pointer(part2)), uintptr(unsafe.Pointer(value)), uintptr(flags), 0)
+	r = (*byte)(unsafe.Pointer(r0))
+	return
+}
+
+func Tcl_UnsetVar(interp *Tcl_Interp, part1 *byte, flags int32) (status int32) {
+	r0, _, _ := syscall.Syscall(procTcl_UnsetVar.Addr(), 3, uintptr(unsafe.Pointer(interp)), uintptr(unsafe.Pointer(part1)), uintptr(flags))
+	status = int32(r0)
+	return
+}
+
+func Tk_Init(interp *Tcl_Interp) (r int32) {
+	r0, _, _ := syscall.Syscall(procTk_Init.Addr(), 1, uintptr(unsafe.Pointer(interp)), 0, 0)
+	r = int32(r0)
+	return
+}
+
+func Tk_MainLoop() {
+	syscall.Syscall(procTk_MainLoop.Addr(), 0, 0, 0, 0)
+	return
+}
+
+func Tk_FindPhoto(interp *Tcl_Interp, imageName *byte) (handle *Tk_PhotoHandle) {
+	r0, _, _ := syscall.Syscall(procTk_FindPhoto.Addr(), 2, uintptr(unsafe.Pointer(interp)), uintptr(unsafe.Pointer(imageName)), 0)
+	handle = (*Tk_PhotoHandle)(unsafe.Pointer(r0))
+	return
+}
+
+func Tk_PhotoBlank(handle *Tk_PhotoHandle) {
+	syscall.Syscall(procTk_PhotoBlank.Addr(), 1, uintptr(unsafe.Pointer(handle)), 0, 0)
+	return
+}
+
+func Tk_PhotoSetSize(interp *Tcl_Interp, handle *Tk_PhotoHandle, width int32, height int32) (status int32) {
+	r0, _, _ := syscall.Syscall6(procTk_PhotoSetSize.Addr(), 4, uintptr(unsafe.Pointer(interp)), uintptr(unsafe.Pointer(handle)), uintptr(width), uintptr(height), 0, 0)
+	status = int32(r0)
+	return
+}
+
+func Tk_PhotoGetSize(hanlde *Tk_PhotoHandle, widthPtr *int32, heightPtr *int32) {
+	syscall.Syscall(procTk_PhotoGetSize.Addr(), 3, uintptr(unsafe.Pointer(hanlde)), uintptr(unsafe.Pointer(widthPtr)), uintptr(unsafe.Pointer(heightPtr)))
+	return
+}
+
+func Tk_PhotoExpand(interp *Tcl_Interp, handle *Tk_PhotoHandle, width int32, height int32) (status int32) {
+	r0, _, _ := syscall.Syscall6(procTk_PhotoExpand.Addr(), 4, uintptr(unsafe.Pointer(interp)), uintptr(unsafe.Pointer(handle)), uintptr(width), uintptr(height), 0, 0)
+	status = int32(r0)
+	return
+}
+
+func Tk_PhotoGetImage(handle *Tk_PhotoHandle, blockPtr *Tk_PhotoImageBlock) (status int32) {
+	r0, _, _ := syscall.Syscall(procTk_PhotoGetImage.Addr(), 2, uintptr(unsafe.Pointer(handle)), uintptr(unsafe.Pointer(blockPtr)), 0)
+	status = int32(r0)
+	return
+}
+
+func Tk_PhotoPutBlock(interp *Tcl_Interp, handle *Tk_PhotoHandle, blockPtr *Tk_PhotoImageBlock, x int32, y int32, width int32, height int32, compRule int32) (status int32) {
+	r0, _, _ := syscall.Syscall9(procTk_PhotoPutBlock.Addr(), 8, uintptr(unsafe.Pointer(interp)), uintptr(unsafe.Pointer(handle)), uintptr(unsafe.Pointer(blockPtr)), uintptr(x), uintptr(y), uintptr(width), uintptr(height), uintptr(compRule), 0)
+	status = int32(r0)
+	return
+}
+
+func Tk_PhotoPutZoomedBlock(interp *Tcl_Interp, handle *Tk_PhotoHandle, blockPtr *Tk_PhotoImageBlock, x int32, y int32, width int32, height int32, zoomX int32, zoomY int32, subsampleX int32, subsampleY int32, compRule int32) (status int32) {
+	r0, _, _ := syscall.Syscall12(procTk_PhotoPutZoomedBlock.Addr(), 12, uintptr(unsafe.Pointer(interp)), uintptr(unsafe.Pointer(handle)), uintptr(unsafe.Pointer(blockPtr)), uintptr(x), uintptr(y), uintptr(width), uintptr(height), uintptr(zoomX), uintptr(zoomY), uintptr(subsampleX), uintptr(subsampleY), uintptr(compRule))
+	status = int32(r0)
+	return
+}

+ 266 - 0
vendor/github.com/visualfc/atk/tk/label.go

@@ -0,0 +1,266 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import "fmt"
+
+// tk::label
+type Label struct {
+	BaseWidget
+}
+
+func NewLabel(parent Widget, text string, attributes ...*WidgetAttr) *Label {
+	theme := checkInitUseTheme(attributes)
+	iid := makeNamedWidgetId(parent, "atk_label")
+	attributes = append(attributes, &WidgetAttr{"text", text})
+	info := CreateWidgetInfo(iid, WidgetTypeLabel, theme, attributes)
+	if info == nil {
+		return nil
+	}
+	w := &Label{}
+	w.id = iid
+	w.info = info
+	RegisterWidget(w)
+	return w
+}
+
+func (w *Label) Attach(id string) error {
+	info, err := CheckWidgetInfo(id, WidgetTypeLabel)
+	if err != nil {
+		return err
+	}
+	w.id = id
+	w.info = info
+	RegisterWidget(w)
+	return nil
+}
+
+func (w *Label) SetBackground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -background $atk_tmp_text", w.id))
+}
+
+func (w *Label) Background() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -background", w.id))
+	return r
+}
+
+func (w *Label) SetBorderWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -borderwidth {%v}", w.id, width))
+}
+
+func (w *Label) BorderWidth() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -borderwidth", w.id))
+	return r
+}
+
+func (w *Label) SetForground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -foreground $atk_tmp_text", w.id))
+}
+
+func (w *Label) Forground() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -foreground", w.id))
+	return r
+}
+
+func (w *Label) SetReliefStyle(relief ReliefStyle) error {
+	return eval(fmt.Sprintf("%v configure -relief {%v}", w.id, relief))
+}
+
+func (w *Label) ReliefStyle() ReliefStyle {
+	r, err := evalAsString(fmt.Sprintf("%v cget -relief", w.id))
+	return parserReliefStyleResult(r, err)
+}
+
+func (w *Label) SetFont(font Font) error {
+	if font == nil {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("%v configure -font {%v}", w.id, font.Id()))
+}
+
+func (w *Label) Font() Font {
+	r, err := evalAsString(fmt.Sprintf("%v cget -font", w.id))
+	return parserFontResult(r, err)
+}
+
+func (w *Label) SetAnchor(anchor Anchor) error {
+	return eval(fmt.Sprintf("%v configure -anchor {%v}", w.id, anchor))
+}
+
+func (w *Label) Anchor() Anchor {
+	r, err := evalAsString(fmt.Sprintf("%v cget -anchor", w.id))
+	return parserAnchorResult(r, err)
+}
+
+func (w *Label) SetJustify(justify Justify) error {
+	return eval(fmt.Sprintf("%v configure -justify {%v}", w.id, justify))
+}
+
+func (w *Label) Justify() Justify {
+	r, err := evalAsString(fmt.Sprintf("%v cget -justify", w.id))
+	return parserJustifyResult(r, err)
+}
+
+func (w *Label) SetWrapLength(wraplength int) error {
+	return eval(fmt.Sprintf("%v configure -wraplength {%v}", w.id, wraplength))
+}
+
+func (w *Label) WrapLength() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -wraplength", w.id))
+	return r
+}
+
+func (w *Label) SetImage(image *Image) error {
+	if image == nil {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("%v configure -image {%v}", w.id, image.Id()))
+}
+
+func (w *Label) Image() *Image {
+	r, err := evalAsString(fmt.Sprintf("%v cget -image", w.id))
+	return parserImageResult(r, err)
+}
+
+func (w *Label) SetCompound(compound Compound) error {
+	return eval(fmt.Sprintf("%v configure -compound {%v}", w.id, compound))
+}
+
+func (w *Label) Compound() Compound {
+	r, err := evalAsString(fmt.Sprintf("%v cget -compound", w.id))
+	return parserCompoundResult(r, err)
+}
+
+func (w *Label) SetText(text string) error {
+	setObjText("atk_tmp_text", text)
+	return eval(fmt.Sprintf("%v configure -text $atk_tmp_text", w.id))
+}
+
+func (w *Label) Text() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -text", w.id))
+	return r
+}
+
+func (w *Label) SetWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -width {%v}", w.id, width))
+}
+
+func (w *Label) Width() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -width", w.id))
+	return r
+}
+
+func (w *Label) SetPaddingN(padx int, pady int) error {
+	if w.info.IsTtk {
+		return eval(fmt.Sprintf("%v configure -padding {%v %v}", w.id, padx, pady))
+	}
+	return eval(fmt.Sprintf("%v configure -padx {%v} -pady {%v}", w.id, padx, pady))
+}
+
+func (w *Label) PaddingN() (int, int) {
+	var r string
+	var err error
+	if w.info.IsTtk {
+		r, err = evalAsString(fmt.Sprintf("%v cget -padding", w.id))
+	} else {
+		r1, _ := evalAsString(fmt.Sprintf("%v cget -padx", w.id))
+		r2, _ := evalAsString(fmt.Sprintf("%v cget -pady", w.id))
+		r = r1 + " " + r2
+	}
+	return parserPaddingResult(r, err)
+}
+
+func (w *Label) SetPadding(pad Pad) error {
+	return w.SetPaddingN(pad.X, pad.Y)
+}
+
+func (w *Label) Padding() Pad {
+	x, y := w.PaddingN()
+	return Pad{x, y}
+}
+
+func (w *Label) SetState(state State) error {
+	return eval(fmt.Sprintf("%v configure -state {%v}", w.id, state))
+}
+
+func (w *Label) State() State {
+	r, err := evalAsString(fmt.Sprintf("%v cget -state", w.id))
+	return parserStateResult(r, err)
+}
+
+func (w *Label) SetTakeFocus(takefocus bool) error {
+	return eval(fmt.Sprintf("%v configure -takefocus {%v}", w.id, boolToInt(takefocus)))
+}
+
+func (w *Label) IsTakeFocus() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -takefocus", w.id))
+	return r
+}
+
+func LabelAttrBackground(color string) *WidgetAttr {
+	return &WidgetAttr{"background", color}
+}
+
+func LabelAttrBorderWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"borderwidth", width}
+}
+
+func LabelAttrForground(color string) *WidgetAttr {
+	return &WidgetAttr{"foreground", color}
+}
+
+func LabelAttrReliefStyle(relief ReliefStyle) *WidgetAttr {
+	return &WidgetAttr{"relief", relief}
+}
+
+func LabelAttrFont(font Font) *WidgetAttr {
+	if font == nil {
+		return nil
+	}
+	return &WidgetAttr{"font", font.Id()}
+}
+
+func LabelAttrAnchor(anchor Anchor) *WidgetAttr {
+	return &WidgetAttr{"anchor", anchor}
+}
+
+func LabelAttrJustify(justify Justify) *WidgetAttr {
+	return &WidgetAttr{"justify", justify}
+}
+
+func LabelAttrWrapLength(wraplength int) *WidgetAttr {
+	return &WidgetAttr{"wraplength", wraplength}
+}
+
+func LabelAttrImage(image *Image) *WidgetAttr {
+	if image == nil {
+		return nil
+	}
+	return &WidgetAttr{"image", image.Id()}
+}
+
+func LabelAttrCompound(compound Compound) *WidgetAttr {
+	return &WidgetAttr{"compound", compound}
+}
+
+func LabelAttrText(text string) *WidgetAttr {
+	return &WidgetAttr{"text", text}
+}
+
+func LabelAttrWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"width", width}
+}
+
+func LabelAttrPadding(padding Pad) *WidgetAttr {
+	return &WidgetAttr{"padding", padding}
+}
+
+func LabelAttrState(state State) *WidgetAttr {
+	return &WidgetAttr{"state", state}
+}
+
+func LabelAttrTakeFocus(takefocus bool) *WidgetAttr {
+	return &WidgetAttr{"takefocus", boolToInt(takefocus)}
+}

+ 160 - 0
vendor/github.com/visualfc/atk/tk/labelframe.go

@@ -0,0 +1,160 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import "fmt"
+
+// label frame
+type LabelFrame struct {
+	BaseWidget
+}
+
+func NewLabelFrame(parent Widget, attributes ...*WidgetAttr) *LabelFrame {
+	theme := checkInitUseTheme(attributes)
+	iid := makeNamedWidgetId(parent, "atk_labelframe")
+	info := CreateWidgetInfo(iid, WidgetTypeLabelFrame, theme, attributes)
+	if info == nil {
+		return nil
+	}
+	w := &LabelFrame{}
+	w.id = iid
+	w.info = info
+	RegisterWidget(w)
+	return w
+}
+
+func (w *LabelFrame) Attach(id string) error {
+	info, err := CheckWidgetInfo(id, WidgetTypeLabelFrame)
+	if err != nil {
+		return err
+	}
+	w.id = id
+	w.info = info
+	RegisterWidget(w)
+	return nil
+}
+
+func (w *LabelFrame) SetLabelText(text string) error {
+	setObjText("atk_tmp_text", text)
+	return eval(fmt.Sprintf("%v configure -text $atk_tmp_text", w.id))
+}
+
+func (w *LabelFrame) LabelText() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -text", w.id))
+	return r
+}
+
+func (w *LabelFrame) SetLabelAnchor(anchor Anchor) error {
+	return eval(fmt.Sprintf("%v configure -labelanchor {%v}", w.id, anchor))
+}
+
+func (w *LabelFrame) LabelAnchor() Anchor {
+	r, err := evalAsString(fmt.Sprintf("%v cget -labelanchor", w.id))
+	return parserAnchorResult(r, err)
+}
+
+func (w *LabelFrame) SetBorderWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -borderwidth {%v}", w.id, width))
+}
+
+func (w *LabelFrame) BorderWidth() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -borderwidth", w.id))
+	return r
+}
+
+func (w *LabelFrame) SetReliefStyle(relief ReliefStyle) error {
+	return eval(fmt.Sprintf("%v configure -relief {%v}", w.id, relief))
+}
+
+func (w *LabelFrame) ReliefStyle() ReliefStyle {
+	r, err := evalAsString(fmt.Sprintf("%v cget -relief", w.id))
+	return parserReliefStyleResult(r, err)
+}
+
+func (w *LabelFrame) SetWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -width {%v}", w.id, width))
+}
+
+func (w *LabelFrame) Width() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -width", w.id))
+	return r
+}
+
+func (w *LabelFrame) SetHeight(height int) error {
+	return eval(fmt.Sprintf("%v configure -height {%v}", w.id, height))
+}
+
+func (w *LabelFrame) Height() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -height", w.id))
+	return r
+}
+
+func (w *LabelFrame) SetPaddingN(padx int, pady int) error {
+	if w.info.IsTtk {
+		return eval(fmt.Sprintf("%v configure -padding {%v %v}", w.id, padx, pady))
+	}
+	return eval(fmt.Sprintf("%v configure -padx {%v} -pady {%v}", w.id, padx, pady))
+}
+
+func (w *LabelFrame) PaddingN() (int, int) {
+	var r string
+	var err error
+	if w.info.IsTtk {
+		r, err = evalAsString(fmt.Sprintf("%v cget -padding", w.id))
+	} else {
+		r1, _ := evalAsString(fmt.Sprintf("%v cget -padx", w.id))
+		r2, _ := evalAsString(fmt.Sprintf("%v cget -pady", w.id))
+		r = r1 + " " + r2
+	}
+	return parserPaddingResult(r, err)
+}
+
+func (w *LabelFrame) SetPadding(pad Pad) error {
+	return w.SetPaddingN(pad.X, pad.Y)
+}
+
+func (w *LabelFrame) Padding() Pad {
+	x, y := w.PaddingN()
+	return Pad{x, y}
+}
+
+func (w *LabelFrame) SetTakeFocus(takefocus bool) error {
+	return eval(fmt.Sprintf("%v configure -takefocus {%v}", w.id, boolToInt(takefocus)))
+}
+
+func (w *LabelFrame) IsTakeFocus() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -takefocus", w.id))
+	return r
+}
+
+func LabelFrameAttrLabelText(text string) *WidgetAttr {
+	return &WidgetAttr{"text", text}
+}
+
+func LabelFrameAttrLabelAnchor(anchor Anchor) *WidgetAttr {
+	return &WidgetAttr{"labelanchor", anchor}
+}
+
+func LabelFrameAttrBorderWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"borderwidth", width}
+}
+
+func LabelFrameAttrReliefStyle(relief ReliefStyle) *WidgetAttr {
+	return &WidgetAttr{"relief", relief}
+}
+
+func LabelFrameAttrWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"width", width}
+}
+
+func LabelFrameAttrHeight(height int) *WidgetAttr {
+	return &WidgetAttr{"height", height}
+}
+
+func LabelFrameAttrPadding(pad Pad) *WidgetAttr {
+	return &WidgetAttr{"pad", pad}
+}
+
+func LabelFrameAttrTakeFocus(takefocus bool) *WidgetAttr {
+	return &WidgetAttr{"takefocus", boolToInt(takefocus)}
+}

+ 148 - 0
vendor/github.com/visualfc/atk/tk/layout.go

@@ -0,0 +1,148 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import "fmt"
+
+type LayoutWidget interface {
+	Widget
+	LayoutWidget() Widget
+}
+
+func checkLayoutWidget(widget Widget) Widget {
+	if w, ok := (widget).(LayoutWidget); ok {
+		return w.LayoutWidget()
+	}
+	return widget
+}
+
+type Layout interface {
+	Widget
+	AddWidget(widget Widget, attrs ...*LayoutAttr) error
+	AddLayout(layout Layout, attrs ...*LayoutAttr) error
+	RemoveWidget(widget Widget) error
+	RemoveLayout(layout Layout) error
+}
+
+type LayoutAttr struct {
+	key   string
+	value interface{}
+}
+
+type LayoutItem struct {
+	widget Widget
+	attrs  []*LayoutAttr
+}
+
+type LayoutSpacer struct {
+	BaseWidget
+	space  int
+	expand bool
+}
+
+func (w *LayoutSpacer) Type() WidgetType {
+	return WidgetTypeLayoutSpacer
+}
+
+func (w *LayoutSpacer) TypeName() string {
+	return "LayoutSpacer"
+}
+
+func (w *LayoutSpacer) SetSpace(space int) error {
+	w.space = space
+	return nil
+}
+
+func (w *LayoutSpacer) Space() int {
+	return w.space
+}
+
+func (w *LayoutSpacer) SetExpand(expand bool) error {
+	w.expand = expand
+	return nil
+}
+
+func (w *LayoutSpacer) IsExpand() bool {
+	return w.expand
+}
+
+// width ignore for PackLayout
+func (w *LayoutSpacer) SetWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -width {%v}", w.id, width))
+}
+
+func (w *LayoutSpacer) Width() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -width", w.id))
+	return r
+}
+
+// height ignore for PackLayout
+func (w *LayoutSpacer) SetHeight(height int) error {
+	return eval(fmt.Sprintf("%v configure -height {%v}", w.id, height))
+}
+
+func (w *LayoutSpacer) Height() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -height", w.id))
+	return r
+}
+
+func NewLayoutSpacer(parent Widget, space int, expand bool) *LayoutSpacer {
+	theme := checkInitUseTheme(nil)
+	iid := makeNamedWidgetId(parent, "atk_layoutspacer")
+	info := CreateWidgetInfo(iid, WidgetTypeFrame, theme, nil)
+	if info == nil {
+		return nil
+	}
+	w := &LayoutSpacer{}
+	w.id = iid
+	w.info = info
+	w.space = space
+	w.expand = expand
+	RegisterWidget(w)
+	return w
+}
+
+type LayoutFrame struct {
+	BaseWidget
+}
+
+func (w *LayoutFrame) Type() WidgetType {
+	return WidgetTypeLayoutFrame
+}
+
+func (w *LayoutFrame) TypeName() string {
+	return "LayoutFrame"
+}
+
+func NewLayoutFrame(parent Widget, attributes ...*WidgetAttr) *LayoutFrame {
+	theme := checkInitUseTheme(attributes)
+	iid := makeNamedWidgetId(parent, "atk_layoutframe")
+	info := CreateWidgetInfo(iid, WidgetTypeFrame, theme, attributes)
+	if info == nil {
+		return nil
+	}
+	w := &LayoutFrame{}
+	w.id = iid
+	w.info = info
+	RegisterWidget(w)
+	return w
+}
+
+func AppendLayoutAttrs(org []*LayoutAttr, attributes ...*LayoutAttr) []*LayoutAttr {
+	var remain []*LayoutAttr
+	var find bool
+	for _, attr := range attributes {
+		find = false
+		for _, old := range org {
+			if old.key == attr.key {
+				old.value = attr.value
+				find = true
+				break
+			}
+		}
+		if !find {
+			remain = append(remain, attr)
+		}
+	}
+	return append(org, remain...)
+}

+ 389 - 0
vendor/github.com/visualfc/atk/tk/listbox.go

@@ -0,0 +1,389 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+	"strings"
+)
+
+// listbox
+type ListBox struct {
+	BaseWidget
+	xscrollcommand *CommandEx
+	yscrollcommand *CommandEx
+}
+
+func NewListBox(parent Widget, attributes ...*WidgetAttr) *ListBox {
+	theme := checkInitUseTheme(attributes)
+	iid := makeNamedWidgetId(parent, "atk_listbox")
+	attributes = append(attributes, &WidgetAttr{"listvariable", variableId(iid)})
+	info := CreateWidgetInfo(iid, WidgetTypeListBox, theme, attributes)
+	if info == nil {
+		return nil
+	}
+	w := &ListBox{}
+	w.id = iid
+	w.info = info
+	evalSetValue(variableId(iid), "")
+	RegisterWidget(w)
+	return w
+}
+
+func (w *ListBox) Attach(id string) error {
+	info, err := CheckWidgetInfo(id, WidgetTypeListBox)
+	if err != nil {
+		return err
+	}
+	w.id = id
+	w.info = info
+	RegisterWidget(w)
+	return nil
+}
+
+func (w *ListBox) SetBackground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -background $atk_tmp_text", w.id))
+}
+
+func (w *ListBox) Background() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -background", w.id))
+	return r
+}
+
+func (w *ListBox) SetBorderWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -borderwidth {%v}", w.id, width))
+}
+
+func (w *ListBox) BorderWidth() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -borderwidth", w.id))
+	return r
+}
+
+func (w *ListBox) SetForground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -foreground $atk_tmp_text", w.id))
+}
+
+func (w *ListBox) Forground() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -foreground", w.id))
+	return r
+}
+
+func (w *ListBox) SetReliefStyle(relief ReliefStyle) error {
+	return eval(fmt.Sprintf("%v configure -relief {%v}", w.id, relief))
+}
+
+func (w *ListBox) ReliefStyle() ReliefStyle {
+	r, err := evalAsString(fmt.Sprintf("%v cget -relief", w.id))
+	return parserReliefStyleResult(r, err)
+}
+
+func (w *ListBox) SetFont(font Font) error {
+	if font == nil {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("%v configure -font {%v}", w.id, font.Id()))
+}
+
+func (w *ListBox) Font() Font {
+	r, err := evalAsString(fmt.Sprintf("%v cget -font", w.id))
+	return parserFontResult(r, err)
+}
+
+func (w *ListBox) SetJustify(justify Justify) error {
+	if !mainInterp.SupportTk86() {
+		return ErrUnsupport
+	}
+	return eval(fmt.Sprintf("%v configure -justify {%v}", w.id, justify))
+}
+
+func (w *ListBox) Justify() Justify {
+	if !mainInterp.SupportTk86() {
+		return JustifyLeft
+	}
+	r, err := evalAsString(fmt.Sprintf("%v cget -justify", w.id))
+	return parserJustifyResult(r, err)
+}
+
+func (w *ListBox) SetWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -width {%v}", w.id, width))
+}
+
+func (w *ListBox) Width() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -width", w.id))
+	return r
+}
+
+func (w *ListBox) SetHeight(height int) error {
+	return eval(fmt.Sprintf("%v configure -height {%v}", w.id, height))
+}
+
+func (w *ListBox) Height() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -height", w.id))
+	return r
+}
+
+func (w *ListBox) SetPaddingN(padx int, pady int) error {
+	if w.info.IsTtk {
+		return eval(fmt.Sprintf("%v configure -padding {%v %v}", w.id, padx, pady))
+	}
+	return eval(fmt.Sprintf("%v configure -padx {%v} -pady {%v}", w.id, padx, pady))
+}
+
+func (w *ListBox) PaddingN() (int, int) {
+	var r string
+	var err error
+	if w.info.IsTtk {
+		r, err = evalAsString(fmt.Sprintf("%v cget -padding", w.id))
+	} else {
+		r1, _ := evalAsString(fmt.Sprintf("%v cget -padx", w.id))
+		r2, _ := evalAsString(fmt.Sprintf("%v cget -pady", w.id))
+		r = r1 + " " + r2
+	}
+	return parserPaddingResult(r, err)
+}
+
+func (w *ListBox) SetPadding(pad Pad) error {
+	return w.SetPaddingN(pad.X, pad.Y)
+}
+
+func (w *ListBox) Padding() Pad {
+	x, y := w.PaddingN()
+	return Pad{x, y}
+}
+
+func (w *ListBox) SetState(state State) error {
+	return eval(fmt.Sprintf("%v configure -state {%v}", w.id, state))
+}
+
+func (w *ListBox) State() State {
+	r, err := evalAsString(fmt.Sprintf("%v cget -state", w.id))
+	return parserStateResult(r, err)
+}
+
+func (w *ListBox) SetSelectMode(mode ListSelectMode) error {
+	return eval(fmt.Sprintf("%v configure -selectmode {%v}", w.id, mode))
+}
+
+func (w *ListBox) SelectMode() ListSelectMode {
+	r, err := evalAsString(fmt.Sprintf("%v cget -selectmode", w.id))
+	return parserListSelectModeResult(r, err)
+}
+
+func (w *ListBox) SetTakeFocus(takefocus bool) error {
+	return eval(fmt.Sprintf("%v configure -takefocus {%v}", w.id, boolToInt(takefocus)))
+}
+
+func (w *ListBox) IsTakeFocus() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -takefocus", w.id))
+	return r
+}
+
+func (w *ListBox) SetItems(items []string) *ListBox {
+	mainInterp.SetStringList(variableId(w.id), items, true)
+	return w
+}
+
+func (w *ListBox) Items() []string {
+	return mainInterp.GetList(variableId(w.id), true).ToStringList()
+}
+
+func (w *ListBox) ItemCount() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v size", w.id))
+	return r
+}
+
+func (w *ListBox) InsertItem(index int, item string) *ListBox {
+	setObjText("atk_tmp_item", item)
+	eval(fmt.Sprintf("%v insert %v $atk_tmp_item", w.id, index))
+	return w
+}
+
+func (w *ListBox) AppendItem(index int, item string) *ListBox {
+	mainInterp.AppendStringList(variableId(w.id), item, true)
+	return w
+}
+
+func (w *ListBox) AppendItems(items []string) *ListBox {
+	mainInterp.AppendStringListList(variableId(w.id), items, true)
+	return w
+}
+
+func (w *ListBox) SetItemText(index int, item string) *ListBox {
+	if index >= 0 && index < w.ItemCount() {
+		setObjText("atk_tmp_item", item)
+		eval(fmt.Sprintf("lset %v %v $atk_tmp_item", variableId(w.id), index))
+	}
+	return w
+}
+
+func (w *ListBox) ItemText(index int) string {
+	r, _ := evalAsString(fmt.Sprintf("%v get %v", w.id, index))
+	return r
+}
+
+func (w *ListBox) RemoveItem(index int) error {
+	err := eval(fmt.Sprintf("%v delete %v %v", w.id, index, index))
+	return err
+}
+
+func (w *ListBox) RemoveItemRange(start int, end int) error {
+	err := eval(fmt.Sprintf("%v delete %v %v", w.id, start, end))
+	return err
+}
+
+func (w *ListBox) SetSelectionRange(start int, end int) *ListBox {
+	eval(fmt.Sprintf("%v selection set %v %v", w.id, start, end))
+	return w
+}
+
+func (w *ListBox) SelectedIndexs() []int {
+	r, _ := evalAsIntList(fmt.Sprintf("%v curselection", w.id))
+	return r
+}
+
+func (w *ListBox) SelectedItems() (items []string) {
+	indexs := w.SelectedIndexs()
+	if indexs == nil {
+		return nil
+	}
+	for _, index := range indexs {
+		items = append(items, w.ItemText(index))
+	}
+	return
+}
+
+func (w *ListBox) ClearSelection() *ListBox {
+	eval(fmt.Sprintf("%v selection clear 0 end", w.id))
+	return w
+}
+
+func (w *ListBox) OnSelectionChanged(fn func()) error {
+	if fn == nil {
+		return ErrInvalid
+	}
+	return w.BindEvent("<<ListboxSelect>>", func(e *Event) {
+		fn()
+	})
+}
+
+func (w *ListBox) SetXViewArgs(args []string) error {
+	return eval(fmt.Sprintf("%v xview %v", w.id, strings.Join(args, " ")))
+}
+
+func (w *ListBox) SetYViewArgs(args []string) error {
+	return eval(fmt.Sprintf("%v yview %v", w.id, strings.Join(args, " ")))
+}
+
+func (w *ListBox) OnXScrollEx(fn func([]string) error) error {
+	if fn == nil {
+		return ErrInvalid
+	}
+	if w.xscrollcommand == nil {
+		w.xscrollcommand = &CommandEx{}
+		bindCommandEx(w.id, "xscrollcommand", w.xscrollcommand.Invoke)
+	}
+	w.xscrollcommand.Bind(fn)
+	return nil
+}
+
+func (w *ListBox) OnYScrollEx(fn func([]string) error) error {
+	if fn == nil {
+		return ErrInvalid
+	}
+	if w.yscrollcommand == nil {
+		w.yscrollcommand = &CommandEx{}
+		bindCommandEx(w.id, "yscrollcommand", w.yscrollcommand.Invoke)
+	}
+	w.yscrollcommand.Bind(fn)
+	return nil
+}
+
+func (w *ListBox) BindXScrollBar(bar *ScrollBar) error {
+	if !IsValidWidget(bar) {
+		return ErrInvalid
+	}
+	w.OnXScrollEx(bar.SetScrollArgs)
+	bar.OnCommandEx(w.SetXViewArgs)
+	return nil
+}
+
+func (w *ListBox) BindYScrollBar(bar *ScrollBar) error {
+	if !IsValidWidget(bar) {
+		return ErrInvalid
+	}
+	w.OnYScrollEx(bar.SetScrollArgs)
+	bar.OnCommandEx(w.SetYViewArgs)
+	return nil
+}
+
+type ListBoxEx struct {
+	*ScrollLayout
+	*ListBox
+}
+
+func NewListBoxEx(parent Widget, attributs ...*WidgetAttr) *ListBoxEx {
+	w := &ListBoxEx{}
+	w.ScrollLayout = NewScrollLayout(parent)
+	w.ListBox = NewListBox(parent, attributs...)
+	w.SetWidget(w.ListBox)
+	w.ListBox.BindXScrollBar(w.XScrollBar)
+	w.ListBox.BindYScrollBar(w.YScrollBar)
+	RegisterWidget(w)
+	return w
+}
+
+func ListBoxAttrBackground(color string) *WidgetAttr {
+	return &WidgetAttr{"background", color}
+}
+
+func ListBoxAttrBorderWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"borderwidth", width}
+}
+
+func ListBoxAttrForground(color string) *WidgetAttr {
+	return &WidgetAttr{"foreground", color}
+}
+
+func ListBoxAttrReliefStyle(relief ReliefStyle) *WidgetAttr {
+	return &WidgetAttr{"relief", relief}
+}
+
+func ListBoxAttrFont(font Font) *WidgetAttr {
+	if font == nil {
+		return nil
+	}
+	return &WidgetAttr{"font", font.Id()}
+}
+
+func ListBoxAttrJustify(justify Justify) *WidgetAttr {
+	if !mainInterp.SupportTk86() {
+		return nil
+	}
+	return &WidgetAttr{"justify", justify}
+}
+
+func ListBoxAttrWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"width", width}
+}
+
+func ListBoxAttrHeight(height int) *WidgetAttr {
+	return &WidgetAttr{"height", height}
+}
+
+func ListBoxAttrPadding(padding Pad) *WidgetAttr {
+	return &WidgetAttr{"padding", padding}
+}
+
+func ListBoxAttrState(state State) *WidgetAttr {
+	return &WidgetAttr{"state", state}
+}
+
+func ListBoxAttrSelectMode(mode ListSelectMode) *WidgetAttr {
+	return &WidgetAttr{"selectmode", mode}
+}
+
+func ListBoxAttrTakeFocus(takefocus bool) *WidgetAttr {
+	return &WidgetAttr{"takefocus", boolToInt(takefocus)}
+}

+ 341 - 0
vendor/github.com/visualfc/atk/tk/menu.go

@@ -0,0 +1,341 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import "fmt"
+
+// menu
+type Menu struct {
+	BaseWidget
+}
+
+func NewMenu(parent Widget, attributes ...*WidgetAttr) *Menu {
+	theme := checkInitUseTheme(attributes)
+	iid := makeNamedWidgetId(parent, "atk_menu")
+	info := CreateWidgetInfo(iid, WidgetTypeMenu, theme, attributes)
+	if info == nil {
+		return nil
+	}
+	w := &Menu{}
+	w.id = iid
+	w.info = info
+	RegisterWidget(w)
+	return w
+}
+
+func (w *Menu) Attach(id string) error {
+	info, err := CheckWidgetInfo(id, WidgetTypeMenu)
+	if err != nil {
+		return err
+	}
+	w.id = id
+	w.info = info
+	RegisterWidget(w)
+	return nil
+}
+
+func (w *Menu) SetFont(font Font) error {
+	if font == nil {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("%v configure -font {%v}", w.id, font.Id()))
+}
+
+func (w *Menu) Font() Font {
+	r, err := evalAsString(fmt.Sprintf("%v cget -font", w.id))
+	return parserFontResult(r, err)
+}
+
+func (w *Menu) SetActiveBackground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -activebackground $atk_tmp_text", w.id))
+}
+
+func (w *Menu) ActiveBackground() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -activebackground", w.id))
+	return r
+}
+
+func (w *Menu) SetActiveForground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -activeforeground $atk_tmp_text", w.id))
+}
+
+func (w *Menu) ActiveForground() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -activeforeground", w.id))
+	return r
+}
+
+func (w *Menu) SetBackground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -background $atk_tmp_text", w.id))
+}
+
+func (w *Menu) Background() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -background", w.id))
+	return r
+}
+
+func (w *Menu) SetForground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -foreground $atk_tmp_text", w.id))
+}
+
+func (w *Menu) Forground() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -foreground", w.id))
+	return r
+}
+
+func (w *Menu) SetSelectColor(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -selectcolor $atk_tmp_text", w.id))
+}
+
+func (w *Menu) SelectColor() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -selectcolor", w.id))
+	return r
+}
+
+func (w *Menu) SetDisabledForground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -disabledforeground $atk_tmp_text", w.id))
+}
+
+func (w *Menu) DisabledForground() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -disabledforeground", w.id))
+	return r
+}
+
+func (w *Menu) SetActiveBorderWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -activeborderwidth {%v}", w.id, width))
+}
+
+func (w *Menu) ActiveBorderWidth() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -activeborderwidth", w.id))
+	return r
+}
+
+func (w *Menu) SetBorderWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -borderwidth {%v}", w.id, width))
+}
+
+func (w *Menu) BorderWidth() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -borderwidth", w.id))
+	return r
+}
+
+func (w *Menu) SetReliefStyle(relief ReliefStyle) error {
+	return eval(fmt.Sprintf("%v configure -relief {%v}", w.id, relief))
+}
+
+func (w *Menu) ReliefStyle() ReliefStyle {
+	r, err := evalAsString(fmt.Sprintf("%v cget -relief", w.id))
+	return parserReliefStyleResult(r, err)
+}
+
+func (w *Menu) SetTearoffTitle(title string) error {
+	setObjText("atk_tmp_text", title)
+	return eval(fmt.Sprintf("%v configure -title $atk_tmp_text", w.id))
+}
+
+func (w *Menu) TearoffTitle() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -title", w.id))
+	return r
+}
+
+func (w *Menu) SetTearoff(tearoff bool) error {
+	return eval(fmt.Sprintf("%v configure -tearoff {%v}", w.id, boolToInt(tearoff)))
+}
+
+func (w *Menu) IsTearoff() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -tearoff", w.id))
+	return r
+}
+
+func (w *Menu) SetTakeFocus(takefocus bool) error {
+	return eval(fmt.Sprintf("%v configure -takefocus {%v}", w.id, boolToInt(takefocus)))
+}
+
+func (w *Menu) IsTakeFocus() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -takefocus", w.id))
+	return r
+}
+
+func (w *Menu) AddSubMenu(label string, sub *Menu) error {
+	setObjText("atk_tmp_label", label)
+	err := eval(fmt.Sprintf("%v add cascade -label $atk_tmp_label -menu {%v}",
+		w.id, sub.id))
+	return err
+}
+
+func (w *Menu) AddNewSubMenu(label string, attributes ...*WidgetAttr) *Menu {
+	sub := NewMenu(w, attributes...)
+	err := w.AddSubMenu(label, sub)
+	if err != nil {
+		return nil
+	}
+	return sub
+}
+
+func (w *Menu) InsertSubMenu(index int, label string, sub *Menu) error {
+	if index < 0 {
+		return w.AddSubMenu(label, sub)
+	}
+	setObjText("atk_tmp_label", label)
+	err := eval(fmt.Sprintf("%v insert %v cascade -label $atk_tmp_label -menu {%v}",
+		w.id, index, sub.id))
+	return err
+}
+
+func (w *Menu) InsertNewSubMenu(index int, label string, attributes ...*WidgetAttr) *Menu {
+	sub := NewMenu(w, attributes...)
+	err := w.InsertSubMenu(index, label, sub)
+	if err != nil {
+		return nil
+	}
+	return sub
+}
+
+func (w *Menu) AddAction(act *Action) error {
+	var script string
+	if act.IsSeparator() {
+		script = fmt.Sprintf("%v add separator", w.id)
+	} else if act.IsRadioAction() {
+		setObjText("atk_tmp_label", act.label)
+		script = fmt.Sprintf("%v add radiobutton -label $atk_tmp_label -variable {%v} -value {%v} -command {%v}",
+			w.id, act.groupid, act.radioid, act.actid)
+	} else if act.IsCheckAction() {
+		setObjText("atk_tmp_label", act.label)
+		script = fmt.Sprintf("%v add checkbutton -label $atk_tmp_label -variable {%v} -command {%v}",
+			w.id, act.checkid, act.actid)
+	} else {
+		setObjText("atk_tmp_label", act.label)
+		script = fmt.Sprintf("%v add command -label $atk_tmp_label -command {%v}",
+			w.id, act.actid)
+	}
+	return eval(script)
+}
+
+func (w *Menu) InsertAction(index int, act *Action) error {
+	if index < 0 {
+		return w.AddAction(act)
+	}
+	setObjText("atk_tmp_label", act.label)
+	var script string
+	if act.IsSeparator() {
+		script = fmt.Sprintf("%v insert %v separator", w.id, index)
+	} else if act.IsRadioAction() {
+		script = fmt.Sprintf("%v insert %v radiobutton -label $atk_tmp_label -variable {%v} -value {%v} -command {%v}",
+			w.id, index, act.groupid, act.radioid, act.actid)
+	} else if act.IsCheckAction() {
+		script = fmt.Sprintf("%v insert %v checkbutton -label $atk_tmp_label -variable {%v} -command {%v}",
+			w.id, index, act.checkid, act.actid)
+	} else {
+		script = fmt.Sprintf("%v insert %v command -label $atk_tmp_label -command {%v}",
+			w.id, index, act.actid)
+	}
+	return eval(script)
+}
+
+func (w *Menu) AddActions(actions []*Action) {
+	for _, act := range actions {
+		w.AddAction(act)
+	}
+}
+
+func (w *Menu) AddSeparator() error {
+	return eval(fmt.Sprintf("%v add separator", w.id))
+}
+
+func (w *Menu) InsertSeparator(index int) error {
+	if index < 0 {
+		return w.AddSeparator()
+	}
+	return eval(fmt.Sprintf("%v insert %v separator", w.id, index))
+}
+
+func parserMenuResult(r string, err error) *Menu {
+	if err != nil {
+		return nil
+	}
+	if r == "" {
+		return nil
+	}
+	if i := FindWidget(r); i != nil {
+		if m, ok := i.(*Menu); ok {
+			return m
+		}
+		return nil
+	}
+	m := &Menu{}
+	if m.Attach(r) != nil {
+		return nil
+	}
+	return m
+}
+
+func SetMenuTearoff(enable bool) {
+	eval(fmt.Sprintf("option add *Menu.tearOff %v", boolToInt(enable)))
+}
+
+func PopupMenu(menu *Menu, xpos int, ypos int) error {
+	if !IsValidWidget(menu) {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("tk_popup %v %v %v", menu.Id(), xpos, ypos))
+}
+
+func MenuAttrFont(font Font) *WidgetAttr {
+	if font == nil {
+		return nil
+	}
+	return &WidgetAttr{"font", font.Id()}
+}
+
+func MenuAttrActiveBackground(color string) *WidgetAttr {
+	return &WidgetAttr{"activebackground", color}
+}
+
+func MenuAttrActiveForground(color string) *WidgetAttr {
+	return &WidgetAttr{"activeforeground", color}
+}
+
+func MenuAttrBackground(color string) *WidgetAttr {
+	return &WidgetAttr{"background", color}
+}
+
+func MenuAttrForground(color string) *WidgetAttr {
+	return &WidgetAttr{"foreground", color}
+}
+
+func MenuAttrSelectColor(color string) *WidgetAttr {
+	return &WidgetAttr{"selectcolor", color}
+}
+
+func MenuAttrDisabledForground(color string) *WidgetAttr {
+	return &WidgetAttr{"disabledforeground", color}
+}
+
+func MenuAttrActiveBorderWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"activeborderwidth", width}
+}
+
+func MenuAttrBorderWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"borderwidth", width}
+}
+
+func MenuAttrReliefStyle(relief ReliefStyle) *WidgetAttr {
+	return &WidgetAttr{"relief", relief}
+}
+
+func MenuAttrTearoffTitle(title string) *WidgetAttr {
+	return &WidgetAttr{"title", title}
+}
+
+func MenuAttrTearoff(tearoff bool) *WidgetAttr {
+	return &WidgetAttr{"tearoff", boolToInt(tearoff)}
+}
+
+func MenuAttrTakeFocus(takefocus bool) *WidgetAttr {
+	return &WidgetAttr{"takefocus", boolToInt(takefocus)}
+}

+ 186 - 0
vendor/github.com/visualfc/atk/tk/menubutton.go

@@ -0,0 +1,186 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import "fmt"
+
+// menubutton
+type MenuButton struct {
+	BaseWidget
+}
+
+func NewMenuButton(parent Widget, text string, attributes ...*WidgetAttr) *MenuButton {
+	theme := checkInitUseTheme(attributes)
+	iid := makeNamedWidgetId(parent, "atk_menubutton")
+	attributes = append(attributes, &WidgetAttr{"text", text})
+	info := CreateWidgetInfo(iid, WidgetTypeMenuButton, theme, attributes)
+	if info == nil {
+		return nil
+	}
+	w := &MenuButton{}
+	w.id = iid
+	w.info = info
+	RegisterWidget(w)
+	return w
+}
+
+func (w *MenuButton) Attach(id string) error {
+	info, err := CheckWidgetInfo(id, WidgetTypeMenuButton)
+	if err != nil {
+		return err
+	}
+	w.id = id
+	w.info = info
+	RegisterWidget(w)
+	return nil
+}
+
+func (w *MenuButton) SetText(text string) error {
+	setObjText("atk_tmp_text", text)
+	return eval(fmt.Sprintf("%v configure -text $atk_tmp_text", w.id))
+}
+
+func (w *MenuButton) Text() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -text", w.id))
+	return r
+}
+
+func (w *MenuButton) SetWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -width {%v}", w.id, width))
+}
+
+func (w *MenuButton) Width() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -width", w.id))
+	return r
+}
+
+func (w *MenuButton) SetImage(image *Image) error {
+	if image == nil {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("%v configure -image {%v}", w.id, image.Id()))
+}
+
+func (w *MenuButton) Image() *Image {
+	r, err := evalAsString(fmt.Sprintf("%v cget -image", w.id))
+	return parserImageResult(r, err)
+}
+
+func (w *MenuButton) SetCompound(compound Compound) error {
+	return eval(fmt.Sprintf("%v configure -compound {%v}", w.id, compound))
+}
+
+func (w *MenuButton) Compound() Compound {
+	r, err := evalAsString(fmt.Sprintf("%v cget -compound", w.id))
+	return parserCompoundResult(r, err)
+}
+
+func (w *MenuButton) SetPaddingN(padx int, pady int) error {
+	if w.info.IsTtk {
+		return eval(fmt.Sprintf("%v configure -padding {%v %v}", w.id, padx, pady))
+	}
+	return eval(fmt.Sprintf("%v configure -padx {%v} -pady {%v}", w.id, padx, pady))
+}
+
+func (w *MenuButton) PaddingN() (int, int) {
+	var r string
+	var err error
+	if w.info.IsTtk {
+		r, err = evalAsString(fmt.Sprintf("%v cget -padding", w.id))
+	} else {
+		r1, _ := evalAsString(fmt.Sprintf("%v cget -padx", w.id))
+		r2, _ := evalAsString(fmt.Sprintf("%v cget -pady", w.id))
+		r = r1 + " " + r2
+	}
+	return parserPaddingResult(r, err)
+}
+
+func (w *MenuButton) SetPadding(pad Pad) error {
+	return w.SetPaddingN(pad.X, pad.Y)
+}
+
+func (w *MenuButton) Padding() Pad {
+	x, y := w.PaddingN()
+	return Pad{x, y}
+}
+
+func (w *MenuButton) SetState(state State) error {
+	return eval(fmt.Sprintf("%v configure -state {%v}", w.id, state))
+}
+
+func (w *MenuButton) State() State {
+	r, err := evalAsString(fmt.Sprintf("%v cget -state", w.id))
+	return parserStateResult(r, err)
+}
+
+func (w *MenuButton) SetTakeFocus(takefocus bool) error {
+	return eval(fmt.Sprintf("%v configure -takefocus {%v}", w.id, boolToInt(takefocus)))
+}
+
+func (w *MenuButton) IsTakeFocus() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -takefocus", w.id))
+	return r
+}
+
+func (w *MenuButton) SetDirection(direction Direction) error {
+	return eval(fmt.Sprintf("%v configure -direction {%v}", w.id, direction))
+}
+
+func (w *MenuButton) Direction() Direction {
+	r, err := evalAsString(fmt.Sprintf("%v cget -direction", w.id))
+	return parserDirectionResult(r, err)
+}
+
+func (w *MenuButton) SetMenu(menu *Menu) error {
+	if menu == nil {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("%v configure -menu {%v}", w.id, menu.Id()))
+}
+
+func (w *MenuButton) Menu() *Menu {
+	r, err := evalAsString(fmt.Sprintf("%v cget -menu", w.id))
+	return parserMenuResult(r, err)
+}
+
+func MenuButtonAttrText(text string) *WidgetAttr {
+	return &WidgetAttr{"text", text}
+}
+
+func MenuButtonAttrWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"width", width}
+}
+
+func MenuButtonAttrImage(image *Image) *WidgetAttr {
+	if image == nil {
+		return nil
+	}
+	return &WidgetAttr{"image", image.Id()}
+}
+
+func MenuButtonAttrCompound(compound Compound) *WidgetAttr {
+	return &WidgetAttr{"compound", compound}
+}
+
+func MenuButtonAttrPadding(padding Pad) *WidgetAttr {
+	return &WidgetAttr{"padding", padding}
+}
+
+func MenuButtonAttrState(state State) *WidgetAttr {
+	return &WidgetAttr{"state", state}
+}
+
+func MenuButtonAttrTakeFocus(takefocus bool) *WidgetAttr {
+	return &WidgetAttr{"takefocus", boolToInt(takefocus)}
+}
+
+func MenuButtonAttrDirection(direction Direction) *WidgetAttr {
+	return &WidgetAttr{"direction", direction}
+}
+
+func MenuButtonAttrMenu(menu *Menu) *WidgetAttr {
+	if menu == nil {
+		return nil
+	}
+	return &WidgetAttr{"menu", menu.Id()}
+}

+ 512 - 0
vendor/github.com/visualfc/atk/tk/misc.go

@@ -0,0 +1,512 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+type Pos struct {
+	X int
+	Y int
+}
+
+type Pad struct {
+	X int
+	Y int
+}
+
+type Size struct {
+	Width  int
+	Height int
+}
+
+type Geometry struct {
+	X      int
+	Y      int
+	Width  int
+	Height int
+}
+
+type Orient int
+
+const (
+	Vertical Orient = iota
+	Horizontal
+)
+
+var (
+	orientName = []string{"vertical", "horizontal"}
+)
+
+func (v Orient) String() string {
+	if v >= 0 && int(v) < len(orientName) {
+		return orientName[v]
+	}
+	return ""
+}
+
+func parserOrientResult(r string, err error) Orient {
+	if err != nil {
+		return -1
+	}
+	for n, s := range orientName {
+		if s == r {
+			return Orient(n)
+		}
+	}
+	return -1
+}
+
+type Justify int
+
+const (
+	JustifyCenter Justify = iota
+	JustifyLeft
+	JustifyRight
+)
+
+var (
+	alignmentName = []string{"center", "left", "right"}
+)
+
+func (v Justify) String() string {
+	if v >= 0 && int(v) < len(alignmentName) {
+		return alignmentName[v]
+	}
+	return ""
+}
+
+func parserJustifyResult(r string, err error) Justify {
+	if err != nil {
+		return -1
+	}
+	for n, s := range alignmentName {
+		if s == r {
+			return Justify(n)
+		}
+	}
+	return -1
+}
+
+type Side int
+
+const (
+	SideLeft Side = iota
+	SideRight
+	SideTop
+	SideBottom
+)
+
+var (
+	sideName = []string{"left", "right", "top", "bottom"}
+)
+
+func (v Side) String() string {
+	if v >= 0 && int(v) < len(sideName) {
+		return sideName[v]
+	}
+	return ""
+}
+
+func parserSideResult(r string, err error) Side {
+	if err != nil {
+		return -1
+	}
+	for n, s := range sideName {
+		if s == r {
+			return Side(n)
+		}
+	}
+	return -1
+}
+
+type BorderMode int
+
+const (
+	BorderModeInside BorderMode = iota
+	BorderModeOutside
+	BorderModeIgnore
+)
+
+var (
+	borderModeName = []string{"inside", "outside", "ignore"}
+)
+
+func (v BorderMode) String() string {
+	if v >= 0 && int(v) < len(borderModeName) {
+		return borderModeName[v]
+	}
+	return ""
+}
+
+func parserBorderModeResult(r string, err error) BorderMode {
+	if err != nil {
+		return -1
+	}
+	for n, s := range borderModeName {
+		if s == r {
+			return BorderMode(n)
+		}
+	}
+	return -1
+}
+
+type Fill int
+
+const (
+	FillNone Fill = iota
+	FillX
+	FillY
+	FillBoth
+)
+
+var (
+	fillName = []string{"none", "x", "y", "both"}
+)
+
+func (v Fill) String() string {
+	if v >= 0 && int(v) < len(fillName) {
+		return fillName[v]
+	}
+	return ""
+}
+
+func parserFillResult(r string, err error) Fill {
+	if err != nil {
+		return -1
+	}
+	for n, s := range fillName {
+		if s == r {
+			return Fill(n)
+		}
+	}
+	return -1
+}
+
+type ReliefStyle int
+
+const (
+	ReliefStyleFlat ReliefStyle = iota
+	ReliefStyleGroove
+	ReliefStyleRaised
+	ReliefStyleRidge
+	ReliefStyleSolid
+	ReliefStyleSunken
+)
+
+var (
+	borderStyleName = []string{"flat", "groove", "raised", "ridge", "solid", "sunken"}
+)
+
+func (v ReliefStyle) String() string {
+	if v >= 0 && int(v) < len(borderStyleName) {
+		return borderStyleName[v]
+	}
+	return ""
+}
+
+func parserReliefStyleResult(r string, err error) ReliefStyle {
+	if err != nil {
+		return -1
+	}
+	for n, s := range borderStyleName {
+		if s == r {
+			return ReliefStyle(n)
+		}
+	}
+	return -1
+}
+
+type Anchor int
+
+const (
+	AnchorCenter Anchor = iota
+	AnchorNorth
+	AnchorEast
+	AnchorSouth
+	AnchorWest
+	AnchorNorthEast
+	AnchorNorthWest
+	AnchorSouthEast
+	AnchorSouthWest
+)
+
+var (
+	anchorName = []string{"center", "n", "e", "s", "w", "ne", "nw", "se", "sw"}
+)
+
+func (v Anchor) String() string {
+	if v >= 0 && int(v) < len(anchorName) {
+		return anchorName[v]
+	}
+	return ""
+}
+
+func parserAnchorResult(r string, err error) Anchor {
+	if err != nil {
+		return -1
+	}
+	for n, s := range anchorName {
+		if s == r {
+			return Anchor(n)
+		}
+	}
+	return -1
+}
+
+type Sticky int
+
+const (
+	StickyCenter Sticky = 1 << iota
+	StickyN
+	StickyS
+	StickyE
+	StickyW
+	StickyNS  = StickyN | StickyS
+	StickyEW  = StickyE | StickyW
+	StickyAll = StickyN | StickyS | StickyE | StickyW
+)
+
+func (v Sticky) String() string {
+	var s string
+	if v&StickyN == StickyN {
+		s += "n"
+	}
+	if v&StickyS == StickyS {
+		s += "s"
+	}
+	if v&StickyE == StickyE {
+		s += "e"
+	}
+	if v&StickyW == StickyW {
+		s += "w"
+	}
+	return s
+}
+
+type Direction int
+
+const (
+	DirectionBelow Direction = iota
+	DirectionAbove
+	DirectionLeft
+	DirectionRight
+)
+
+var (
+	directionName = []string{"below", "above", "left", "right"}
+)
+
+func (v Direction) String() string {
+	if v >= 0 && int(v) < len(directionName) {
+		return directionName[v]
+	}
+	return ""
+}
+
+func parserDirectionResult(r string, err error) Direction {
+	if err != nil {
+		return 0
+	}
+	for n, s := range directionName {
+		if s == r {
+			return Direction(n)
+		}
+	}
+	return 0
+}
+
+type Compound int
+
+const (
+	CompoundNone Compound = iota
+	CompoundTop
+	CompoundBottom
+	CompoundLeft
+	CompoundRight
+	CompoundCenter
+)
+
+var (
+	compoundName = []string{"none", "top", "bottom", "left", "right", "center"}
+)
+
+func (v Compound) String() string {
+	if v >= 0 && int(v) < len(compoundName) {
+		return compoundName[v]
+	}
+	return ""
+}
+
+func parserCompoundResult(r string, err error) Compound {
+	if err != nil {
+		return 0
+	}
+	for n, s := range compoundName {
+		if s == r {
+			return Compound(n)
+		}
+	}
+	return 0
+}
+
+type State int
+
+const (
+	StateNormal State = iota
+	StateActive
+	StateDisable
+	StateReadOnly
+)
+
+var (
+	stateName = []string{"normal", "active", "disabled", "readonly"}
+)
+
+func (v State) String() string {
+	if v >= 0 && int(v) < len(stateName) {
+		return stateName[v]
+	}
+	return ""
+}
+
+func parserStateResult(r string, err error) State {
+	if err != nil {
+		return 0
+	}
+	for n, s := range stateName {
+		if s == r {
+			return State(n)
+		}
+	}
+	return 0
+}
+
+type ListSelectMode int
+
+const (
+	ListSelectSingle ListSelectMode = iota
+	ListSelectBrowse
+	ListSelectMultiple
+	ListSelectExtended
+)
+
+var (
+	listSelectName = []string{"single", "browse", "multiple", "extended"}
+)
+
+func (v ListSelectMode) String() string {
+	if v >= 0 && int(v) < len(listSelectName) {
+		return listSelectName[v]
+	}
+	return ""
+}
+
+func parserListSelectModeResult(r string, err error) ListSelectMode {
+	if err != nil {
+		return 0
+	}
+	for n, s := range listSelectName {
+		if s == r {
+			return ListSelectMode(n)
+		}
+	}
+	return 0
+}
+
+type DisplyCursor int
+
+const (
+	DisplyCursorNone DisplyCursor = iota
+	DisplyCursorHollow
+	DisplyCursorSolid
+)
+
+var (
+	displyCursorName = []string{"none", "hollow", "solid"}
+)
+
+func (v DisplyCursor) String() string {
+	if v >= 0 && int(v) < len(displyCursorName) {
+		return displyCursorName[v]
+	}
+	return ""
+}
+
+func parserDisplyCursorResult(r string, err error) DisplyCursor {
+	if err != nil {
+		return 0
+	}
+	for n, s := range displyCursorName {
+		if s == r {
+			return DisplyCursor(n)
+		}
+	}
+	return 0
+}
+
+type LineWrapMode int
+
+const (
+	LineWrapNone LineWrapMode = iota
+	LineWrapChar
+	LineWrapWord
+)
+
+var (
+	lineWrapName = []string{"none", "char", "word"}
+)
+
+func (v LineWrapMode) String() string {
+	if v >= 0 && int(v) < len(lineWrapName) {
+		return lineWrapName[v]
+	}
+	return ""
+}
+
+func parserLineWrapModeResult(r string, err error) LineWrapMode {
+	if err != nil {
+		return 0
+	}
+	for n, s := range lineWrapName {
+		if s == r {
+			return LineWrapMode(n)
+		}
+	}
+	return 0
+}
+
+type TreeSelectMode int
+
+const (
+	TreeSelectExtended TreeSelectMode = iota
+	TreeSelectBrowse
+	TreeSelectNode
+)
+
+var (
+	treeSelectName = []string{"extended", "browse", "none"}
+)
+
+func (v TreeSelectMode) String() string {
+	if v >= 0 && int(v) < len(treeSelectName) {
+		return treeSelectName[v]
+	}
+	return ""
+}
+
+func parserTreeSelectModeResult(r string, err error) TreeSelectMode {
+	if err != nil {
+		return 0
+	}
+	for n, s := range treeSelectName {
+		if s == r {
+			return TreeSelectMode(n)
+		}
+	}
+	return 0
+}
+
+func parserPaddingResult(r string, err error) (int, int) {
+	if err != nil {
+		return 0, 0
+	}
+	return parserTwoInt(r)
+}

+ 257 - 0
vendor/github.com/visualfc/atk/tk/notebook.go

@@ -0,0 +1,257 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+	"strings"
+)
+
+// notebook
+type Notebook struct {
+	BaseWidget
+}
+
+func NewNotebook(parent Widget, attributes ...*WidgetAttr) *Notebook {
+	theme := checkInitUseTheme(attributes)
+	iid := makeNamedWidgetId(parent, "atk_notebook")
+	info := CreateWidgetInfo(iid, WidgetTypeNotebook, theme, attributes)
+	if info == nil {
+		return nil
+	}
+	w := &Notebook{}
+	w.id = iid
+	w.info = info
+	RegisterWidget(w)
+	return w
+}
+
+func (w *Notebook) Attach(id string) error {
+	info, err := CheckWidgetInfo(id, WidgetTypeNotebook)
+	if err != nil {
+		return err
+	}
+	w.id = id
+	w.info = info
+	RegisterWidget(w)
+	return nil
+}
+
+func (w *Notebook) SetWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -width {%v}", w.id, width))
+}
+
+func (w *Notebook) Width() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -width", w.id))
+	return r
+}
+
+func (w *Notebook) SetHeight(height int) error {
+	return eval(fmt.Sprintf("%v configure -height {%v}", w.id, height))
+}
+
+func (w *Notebook) Height() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -height", w.id))
+	return r
+}
+
+func (w *Notebook) SetTakeFocus(takefocus bool) error {
+	return eval(fmt.Sprintf("%v configure -takefocus {%v}", w.id, boolToInt(takefocus)))
+}
+
+func (w *Notebook) IsTakeFocus() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -takefocus", w.id))
+	return r
+}
+
+func (w *Notebook) SetPaddingN(padx int, pady int) error {
+	if w.info.IsTtk {
+		return eval(fmt.Sprintf("%v configure -padding {%v %v}", w.id, padx, pady))
+	}
+	return eval(fmt.Sprintf("%v configure -padx {%v} -pady {%v}", w.id, padx, pady))
+}
+
+func (w *Notebook) PaddingN() (int, int) {
+	var r string
+	var err error
+	if w.info.IsTtk {
+		r, err = evalAsString(fmt.Sprintf("%v cget -padding", w.id))
+	} else {
+		r1, _ := evalAsString(fmt.Sprintf("%v cget -padx", w.id))
+		r2, _ := evalAsString(fmt.Sprintf("%v cget -pady", w.id))
+		r = r1 + " " + r2
+	}
+	return parserPaddingResult(r, err)
+}
+
+func (w *Notebook) SetPadding(pad Pad) error {
+	return w.SetPaddingN(pad.X, pad.Y)
+}
+
+func (w *Notebook) Padding() Pad {
+	x, y := w.PaddingN()
+	return Pad{x, y}
+}
+
+var (
+	tabAttributes = []string{
+		"padding",
+		"state",
+		"sticky",
+		"text",
+		"image",
+		"compound",
+	}
+)
+
+func isTabAttributes(attr string) bool {
+	for _, v := range tabAttributes {
+		if v == attr {
+			return true
+		}
+	}
+	return false
+}
+
+func buildTabAttributeScript(ttk bool, attributes ...*WidgetAttr) string {
+	var list []string
+	for _, attr := range attributes {
+		if attr == nil {
+			continue
+		}
+		if attr.key == "padding" {
+			list = append(list, checkPaddingScript(ttk, attr))
+			continue
+		}
+		if !isTabAttributes(attr.key) {
+			continue
+		}
+		if s, ok := attr.value.(string); ok {
+			pname := "atk_tmp_" + attr.key
+			setObjText(pname, s)
+			list = append(list, fmt.Sprintf("-%v $%v", attr.key, pname))
+			continue
+		}
+		list = append(list, fmt.Sprintf("-%v {%v}", attr.key, attr.value))
+	}
+	return strings.Join(list, " ")
+}
+
+func (w *Notebook) AddTab(widget Widget, text string, attributes ...*WidgetAttr) error {
+	if !IsValidWidget(widget) {
+		return ErrInvalid
+	}
+	attributes = append(attributes, &WidgetAttr{"text", text})
+	extra := buildTabAttributeScript(w.info.IsTtk, attributes...)
+	script := fmt.Sprintf("%v add %v", w.id, widget.Id())
+	if extra != "" {
+		script += " " + extra
+	}
+	return eval(script)
+}
+
+func (w *Notebook) InsertTab(pos int, widget Widget, text string, attributes ...*WidgetAttr) error {
+	if !IsValidWidget(widget) {
+		return ErrInvalid
+	}
+	attributes = append(attributes, &WidgetAttr{"text", text})
+	extra := buildTabAttributeScript(w.info.IsTtk, attributes...)
+	script := fmt.Sprintf("%v insert %v %v", w.id, pos, widget.Id())
+	if extra != "" {
+		script += " " + extra
+	}
+	return eval(script)
+}
+
+func (w *Notebook) SetTab(widget Widget, text string, attributes ...*WidgetAttr) error {
+	if !IsValidWidget(widget) {
+		return ErrInvalid
+	}
+	attributes = append(attributes, &WidgetAttr{"text", text})
+	extra := buildTabAttributeScript(w.info.IsTtk, attributes...)
+	script := fmt.Sprintf("%v tab %v", w.id, widget.Id())
+	if extra != "" {
+		script += " " + extra
+	}
+	return eval(script)
+}
+
+func (w *Notebook) RemoveTab(widget Widget) error {
+	if !IsValidWidget(widget) {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("%v forget %v", w.id, widget.Id()))
+}
+
+func (w *Notebook) SetCurrentTab(widget Widget) error {
+	if !IsValidWidget(widget) {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("%v select %v", w.id, widget.Id()))
+}
+
+func (w *Notebook) CurrentTab() Widget {
+	r, _ := evalAsString(fmt.Sprintf("%v select", w.id))
+	return FindWidget(r)
+}
+
+func (w *Notebook) CurrentTabIndex() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v index current", w.id))
+	return r
+}
+
+func (w *Notebook) TabCount() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v index end", w.id))
+	return r
+}
+
+func (w *Notebook) TabIndex(widget Widget) int {
+	if !IsValidWidget(widget) {
+		return -1
+	}
+	r, _ := evalAsInt(fmt.Sprintf("%v index %v", w.id, widget.Id()))
+	return r
+}
+
+func TabAttrState(state State) *WidgetAttr {
+	return &WidgetAttr{"state", state}
+}
+
+func TabAttrSticky(sticky Sticky) *WidgetAttr {
+	return &WidgetAttr{"sticky", sticky}
+}
+
+func TabAttrPadding(padding Pad) *WidgetAttr {
+	return &WidgetAttr{"padding", padding}
+}
+
+func TabAttrText(text string) *WidgetAttr {
+	return &WidgetAttr{"text", text}
+}
+
+func TabAttrImage(image *Image) *WidgetAttr {
+	if image == nil {
+		return nil
+	}
+	return &WidgetAttr{"image", image.Id()}
+}
+
+func TabAttrCompound(compound Compound) *WidgetAttr {
+	return &WidgetAttr{"compound", compound}
+}
+
+func NotebookAttrWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"width", width}
+}
+
+func NotebookAttrHeight(height int) *WidgetAttr {
+	return &WidgetAttr{"height", height}
+}
+
+func NotebookAttrTakeFocus(takefocus bool) *WidgetAttr {
+	return &WidgetAttr{"takefocus", boolToInt(takefocus)}
+}
+
+func NotebookAttrPadding(padding Pad) *WidgetAttr {
+	return &WidgetAttr{"padding", padding}
+}

+ 148 - 0
vendor/github.com/visualfc/atk/tk/pack.go

@@ -0,0 +1,148 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+	"strings"
+)
+
+func PackAttrSide(side Side) *LayoutAttr {
+	return &LayoutAttr{"side", side}
+}
+
+func PackAttrSideLeft() *LayoutAttr {
+	return &LayoutAttr{"side", "left"}
+}
+
+func PackAttrSideRight() *LayoutAttr {
+	return &LayoutAttr{"side", "right"}
+}
+
+func PackAttrSideTop() *LayoutAttr {
+	return &LayoutAttr{"side", "top"}
+}
+
+func PackAttrSideBottom() *LayoutAttr {
+	return &LayoutAttr{"side", "bottom"}
+}
+
+func PackAttrPadx(padx int) *LayoutAttr {
+	return &LayoutAttr{"padx", padx}
+}
+
+func PackAttrPady(pady int) *LayoutAttr {
+	return &LayoutAttr{"pady", pady}
+}
+
+func PackAttrIpadx(padx int) *LayoutAttr {
+	return &LayoutAttr{"ipadx", padx}
+}
+
+func PackAttrIpady(pady int) *LayoutAttr {
+	return &LayoutAttr{"ipady", pady}
+}
+
+func PackAttrAnchor(anchor Anchor) *LayoutAttr {
+	v := anchor.String()
+	if v == "" {
+		return nil
+	}
+	return &LayoutAttr{"anchor", v}
+}
+
+func PackAttrExpand(b bool) *LayoutAttr {
+	return &LayoutAttr{"expand", boolToInt(b)}
+}
+
+func PackAttrFill(fill Fill) *LayoutAttr {
+	return &LayoutAttr{"fill", fill}
+}
+
+func PackAttrFillX() *LayoutAttr {
+	return &LayoutAttr{"fill", "x"}
+}
+
+func PackAttrFillY() *LayoutAttr {
+	return &LayoutAttr{"fill", "y"}
+}
+
+func PackAttrFillBoth() *LayoutAttr {
+	return &LayoutAttr{"fill", "both"}
+}
+
+func PackAttrFillNone() *LayoutAttr {
+	return &LayoutAttr{"fill", "none"}
+}
+
+func PackAttrBefore(w Widget) *LayoutAttr {
+	if !IsValidWidget(w) {
+		return nil
+	}
+	return &LayoutAttr{"before", w.Id()}
+}
+
+func PackAttrAfter(w Widget) *LayoutAttr {
+	if !IsValidWidget(w) {
+		return nil
+	}
+	return &LayoutAttr{"after", w.Id()}
+}
+
+func PackAttrInMaster(w Widget) *LayoutAttr {
+	if !IsValidWidget(w) {
+		return nil
+	}
+	return &LayoutAttr{"in", w.Id()}
+}
+
+var (
+	packAttrKeys = []string{
+		"side",
+		"padx", "pady",
+		"ipadx", "ipady",
+		"anchor",
+		"expand",
+		"fill",
+		"before",
+		"after",
+		"in",
+	}
+)
+
+func Pack(widget Widget, attributes ...*LayoutAttr) error {
+	return PackList([]Widget{widget}, attributes...)
+}
+
+func PackRemove(widget Widget) error {
+	if !IsValidWidget(widget) {
+		return ErrInvalid
+	}
+	widget = checkLayoutWidget(widget)
+	return eval("pack forget " + widget.Id())
+}
+
+func PackList(widgets []Widget, attributes ...*LayoutAttr) error {
+	var idList []string
+	for _, w := range widgets {
+		if IsValidWidget(w) {
+			w = checkLayoutWidget(w)
+			idList = append(idList, w.Id())
+		}
+	}
+	if len(idList) == 0 {
+		return ErrInvalid
+	}
+	var attrList []string
+	for _, attr := range attributes {
+		if attr == nil || !isValidKey(attr.key, packAttrKeys) {
+			continue
+		}
+		attrList = append(attrList, fmt.Sprintf("-%v {%v}", attr.key, attr.value))
+	}
+	script := fmt.Sprintf("pack %v", strings.Join(idList, " "))
+	if len(attrList) > 0 {
+		script += " " + strings.Join(attrList, " ")
+	}
+	return eval(script)
+}

+ 196 - 0
vendor/github.com/visualfc/atk/tk/packlayout.go

@@ -0,0 +1,196 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+)
+
+type PackLayout struct {
+	*LayoutFrame
+	side  Side
+	pad   *Pad
+	items []*LayoutItem
+}
+
+func (w *PackLayout) SetSide(side Side) error {
+	w.side = side
+	return w.Repack()
+}
+
+func (w *PackLayout) SetPadding(pad Pad) error {
+	return w.SetPaddingN(pad.X, pad.Y)
+}
+
+func (w *PackLayout) SetPaddingN(padx int, pady int) error {
+	w.pad = &Pad{padx, pady}
+	return w.Repack()
+}
+
+func (w *PackLayout) removeItem(widget Widget) error {
+	n := w.indexOfWidget(widget)
+	if n == -1 {
+		return ErrInvalid
+	}
+	PackRemove(widget)
+	w.items = append(w.items[:n], w.items[n+1:]...)
+	return nil
+}
+
+func (w *PackLayout) indexOfWidget(widget Widget) int {
+	for n, v := range w.items {
+		if v.widget == widget {
+			return n
+		}
+	}
+	return -1
+}
+
+func (w *PackLayout) AddWidget(widget Widget, attributes ...*LayoutAttr) error {
+	if !IsValidWidget(widget) {
+		return ErrInvalid
+	}
+	n := w.indexOfWidget(widget)
+	if n != -1 {
+		w.items = append(w.items[:n], w.items[n+1:]...)
+	}
+	w.items = append(w.items, &LayoutItem{widget, attributes})
+	return w.Repack()
+}
+
+func (w *PackLayout) InsertWidget(index int, widget Widget, attributes ...*LayoutAttr) error {
+	if index < 0 {
+		return w.AddWidget(widget, attributes...)
+	}
+	n := w.indexOfWidget(widget)
+	if n != -1 {
+		if n == index {
+			return ErrExist
+		}
+		w.items = append(w.items[:n], w.items[n+1:]...)
+	}
+	if index >= len(w.items) {
+		return w.AddWidget(widget, attributes...)
+	}
+	w.items = append(w.items[:index], append([]*LayoutItem{&LayoutItem{widget, attributes}}, w.items[index:]...)...)
+	return w.Repack()
+}
+
+func (w *PackLayout) AddWidgetEx(widget Widget, fill Fill, expand bool, anchor Anchor) error {
+	return w.AddWidget(widget,
+		PackAttrFill(fill), PackAttrExpand(expand),
+		PackAttrAnchor(anchor))
+}
+
+func (w *PackLayout) InsertWidgetEx(index int, widget Widget, fill Fill, expand bool, anchor Anchor) error {
+	return w.InsertWidget(index, widget,
+		PackAttrFill(fill), PackAttrExpand(expand),
+		PackAttrAnchor(anchor))
+}
+
+func (w *PackLayout) AddWidgets(widgets ...Widget) error {
+	for _, widget := range widgets {
+		n := w.indexOfWidget(widget)
+		if n != -1 {
+			w.items = append(w.items[:n], w.items[n+1:]...)
+		}
+		w.items = append(w.items, &LayoutItem{widget, nil})
+	}
+	return w.Repack()
+}
+
+func (w *PackLayout) AddWidgetList(widgets []Widget, attributes ...*LayoutAttr) error {
+	for _, widget := range widgets {
+		n := w.indexOfWidget(widget)
+		if n != -1 {
+			w.items = append(w.items[:n], w.items[n+1:]...)
+		}
+		w.items = append(w.items, &LayoutItem{widget, attributes})
+	}
+	return w.Repack()
+}
+
+func (w *PackLayout) RemoveWidget(widget Widget) error {
+	if !IsValidWidget(widget) {
+		return ErrInvalid
+	}
+	return w.removeItem(widget)
+}
+
+func (w *PackLayout) SetWidgetAttr(widget Widget, attributes ...*LayoutAttr) error {
+	if !IsValidWidget(widget) {
+		return ErrInvalid
+	}
+	n := w.indexOfWidget(widget)
+	if n == -1 {
+		return ErrInvalid
+	}
+	w.items[n].attrs = attributes
+	return w.Repack()
+}
+
+func (w *PackLayout) itemAttr() []*LayoutAttr {
+	itemsAttr := []*LayoutAttr{PackAttrSide(w.side), PackAttrInMaster(w)}
+	if w.pad != nil {
+		itemsAttr = append(itemsAttr, PackAttrPadx(w.pad.X), PackAttrPady(w.pad.Y))
+	}
+	return itemsAttr
+}
+
+func (w *PackLayout) resetSpacerAttr(item *LayoutItem, s *LayoutSpacer) {
+	if s.IsExpand() {
+		s.SetWidth(0)
+		s.SetHeight(0)
+		if w.side == SideTop || w.side == SideBottom {
+			item.attrs = AppendLayoutAttrs(item.attrs, PackAttrFillY(), PackAttrExpand(true))
+		} else {
+			item.attrs = AppendLayoutAttrs(item.attrs, PackAttrFillX(), PackAttrExpand(true))
+		}
+	} else {
+		item.attrs = AppendLayoutAttrs(item.attrs, PackAttrFillNone(), PackAttrExpand(false))
+		if w.side == SideTop || w.side == SideBottom {
+			s.SetHeight(s.space)
+			s.SetWidth(0)
+		} else {
+			s.SetWidth(s.space)
+			s.SetHeight(0)
+		}
+	}
+}
+
+func (w *PackLayout) Repack() error {
+	for _, item := range w.items {
+		if item.widget == nil {
+			continue
+		}
+		if s, ok := item.widget.(*LayoutSpacer); ok {
+			w.resetSpacerAttr(item, s)
+		}
+		Pack(item.widget, AppendLayoutAttrs(item.attrs, w.itemAttr()...)...)
+	}
+	return Pack(w, PackAttrFill(FillBoth), PackAttrExpand(true))
+}
+
+func (w *PackLayout) SetBorderWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -borderwidth {%v}", w.Id(), width))
+}
+
+func (w *PackLayout) BorderWidth() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -borderwidth", w.Id()))
+	return r
+}
+
+func NewPackLayout(parent Widget, side Side) *PackLayout {
+	pack := &PackLayout{NewLayoutFrame(parent), side, nil, nil}
+	pack.Lower(nil)
+	pack.Repack()
+	return pack
+}
+
+func NewHPackLayout(parent Widget) *PackLayout {
+	return NewPackLayout(parent, SideLeft)
+}
+
+func NewVPackLayout(parent Widget) *PackLayout {
+	return NewPackLayout(parent, SideTop)
+}

+ 83 - 0
vendor/github.com/visualfc/atk/tk/paned.go

@@ -0,0 +1,83 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import "fmt"
+
+// panedwindow
+type Paned struct {
+	BaseWidget
+}
+
+func NewPaned(parent Widget, orient Orient, attributes ...*WidgetAttr) *Paned {
+	iid := makeNamedWidgetId(parent, "atk_paned")
+	attributes = append(attributes, &WidgetAttr{"orient", orient})
+	info := CreateWidgetInfo(iid, WidgetTypePaned, true, attributes)
+	if info == nil {
+		return nil
+	}
+	w := &Paned{}
+	w.id = iid
+	w.info = info
+	RegisterWidget(w)
+	return w
+}
+
+func (w *Paned) Attach(id string) error {
+	info, err := CheckWidgetInfo(id, WidgetTypePaned)
+	if err != nil {
+		return err
+	}
+	w.id = id
+	w.info = info
+	RegisterWidget(w)
+	return nil
+}
+
+func (w *Paned) SetWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -width {%v}", w.id, width))
+}
+
+func (w *Paned) Width() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -width", w.id))
+	return r
+}
+
+func (w *Paned) SetHeight(height int) error {
+	return eval(fmt.Sprintf("%v configure -height {%v}", w.id, height))
+}
+
+func (w *Paned) Height() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -height", w.id))
+	return r
+}
+
+func (w *Paned) AddWidget(widget Widget, weight int) error {
+	if !IsValidWidget(widget) {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("%v add %v -weight %v", w.id, widget.Id(), weight))
+}
+
+func (w *Paned) InsertWidget(pane int, widget Widget, weight int) error {
+	if !IsValidWidget(widget) {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("%v insert %v %v -weight %v", w.id, pane, widget.Id(), weight))
+}
+
+func (w *Paned) SetPane(pane int, weight int) error {
+	return eval(fmt.Sprintf("%v pane %v -weight %v", w.id, pane, weight))
+}
+
+func (w *Paned) RemovePane(pane int) error {
+	return eval(fmt.Sprintf("%v forget %v", w.id, pane))
+}
+
+func PanedAttrWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"width", width}
+}
+
+func PanedAttrHeight(height int) *WidgetAttr {
+	return &WidgetAttr{"height", height}
+}

+ 101 - 0
vendor/github.com/visualfc/atk/tk/place.go

@@ -0,0 +1,101 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+	"strings"
+)
+
+func PlaceAttrAnchor(anchor Anchor) *LayoutAttr {
+	v := anchor.String()
+	if v == "" {
+		return nil
+	}
+	return &LayoutAttr{"anchor", v}
+}
+
+func PlaceAttrBorderMode(mode BorderMode) *LayoutAttr {
+	v := mode.String()
+	if v == "" {
+		return nil
+	}
+	return &LayoutAttr{"bordermode", v}
+}
+
+func PlaceAttrWidth(size int) *LayoutAttr {
+	return &LayoutAttr{"width", size}
+}
+
+func PlaceAttrHeight(size int) *LayoutAttr {
+	return &LayoutAttr{"height", size}
+}
+
+func PlaceAttrRelWidth(size float64) *LayoutAttr {
+	return &LayoutAttr{"relwidth", size}
+}
+
+func PlaceAttrRelHeight(size float64) *LayoutAttr {
+	return &LayoutAttr{"relheight", size}
+}
+
+func PlaceAttrX(location int) *LayoutAttr {
+	return &LayoutAttr{"x", location}
+}
+
+func PlaceAttrY(location int) *LayoutAttr {
+	return &LayoutAttr{"y", location}
+}
+
+func PlaceAttrRelX(location float64) *LayoutAttr {
+	return &LayoutAttr{"relx", location}
+}
+
+func PlaceAttrRelY(location float64) *LayoutAttr {
+	return &LayoutAttr{"rely", location}
+}
+
+func PlaceAttrInMaster(w Widget) *LayoutAttr {
+	if !IsValidWidget(w) {
+		return nil
+	}
+	return &LayoutAttr{"in", w.Id()}
+}
+
+var (
+	placeAttrKeys = []string{
+		"anchor",
+		"bordermode",
+		"x", "y",
+		"relx", "rely",
+		"width", "height",
+		"relwidth", "relheight",
+		"in",
+	}
+)
+
+func Place(widget Widget, attributes ...*LayoutAttr) error {
+	if !IsValidWidget(widget) {
+		return ErrInvalid
+	}
+	var attrList []string
+	for _, attr := range attributes {
+		if attr == nil || !isValidKey(attr.key, placeAttrKeys) {
+			continue
+		}
+		attrList = append(attrList, fmt.Sprintf("-%v {%v}", attr.key, attr.value))
+	}
+	script := fmt.Sprintf("place %v", widget.Id())
+	if len(attrList) > 0 {
+		script += " " + strings.Join(attrList, " ")
+	}
+	return eval(script)
+}
+
+func PlaceRemove(widget Widget) error {
+	if !IsValidWidget(widget) {
+		return ErrInvalid
+	}
+	widget = checkLayoutWidget(widget)
+	return eval("place forget " + widget.Id())
+}

+ 93 - 0
vendor/github.com/visualfc/atk/tk/placeframe.go

@@ -0,0 +1,93 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+type PlaceFrame struct {
+	*Frame
+	items []*LayoutItem
+}
+
+func (w *PlaceFrame) removeItem(widget Widget) error {
+	n := w.indexOfWidget(widget)
+	if n == -1 {
+		return ErrInvalid
+	}
+	PlaceRemove(widget)
+	w.items = append(w.items[:n], w.items[n+1:]...)
+	return nil
+}
+
+func (w *PlaceFrame) indexOfWidget(widget Widget) int {
+	for n, v := range w.items {
+		if v.widget == widget {
+			return n
+		}
+	}
+	return -1
+}
+
+func (w *PlaceFrame) AddWidget(widget Widget, attributes ...*LayoutAttr) error {
+	if !IsValidWidget(widget) {
+		return ErrInvalid
+	}
+	n := w.indexOfWidget(widget)
+	if n != -1 {
+		w.items = append(w.items[:n], w.items[n+1:]...)
+	}
+	w.items = append(w.items, &LayoutItem{widget, attributes})
+	return w.Repack()
+}
+
+func (w *PlaceFrame) InsertWidget(index int, widget Widget, attributes ...*LayoutAttr) error {
+	if index < 0 {
+		return w.AddWidget(widget, attributes...)
+	}
+	n := w.indexOfWidget(widget)
+	if n != -1 {
+		if n == index {
+			return ErrExist
+		}
+		w.items = append(w.items[:n], w.items[n+1:]...)
+	}
+	if index >= len(w.items) {
+		return w.AddWidget(widget, attributes...)
+	}
+	w.items = append(w.items[:index], append([]*LayoutItem{&LayoutItem{widget, attributes}}, w.items[index:]...)...)
+	return w.Repack()
+}
+
+func (w *PlaceFrame) RemoveWidget(widget Widget) error {
+	if !IsValidWidget(widget) {
+		return ErrInvalid
+	}
+	return w.removeItem(widget)
+}
+
+func (w *PlaceFrame) SetWidgetAttr(widget Widget, attributes ...*LayoutAttr) error {
+	if !IsValidWidget(widget) {
+		return ErrInvalid
+	}
+	n := w.indexOfWidget(widget)
+	if n == -1 {
+		return ErrInvalid
+	}
+	w.items[n].attrs = attributes
+	return w.Repack()
+}
+
+func (w *PlaceFrame) Repack() error {
+	for _, item := range w.items {
+		if item.widget == nil {
+			continue
+		}
+		Place(item.widget, AppendLayoutAttrs(item.attrs, PlaceAttrInMaster(w))...)
+	}
+	return Pack(w, PackAttrFill(FillBoth), PackAttrExpand(true))
+}
+
+func NewPlaceFrame(parent Widget) *PlaceFrame {
+	place := &PlaceFrame{NewFrame(parent), nil}
+	place.Lower(nil)
+	place.Repack()
+	return place
+}

+ 138 - 0
vendor/github.com/visualfc/atk/tk/progressbar.go

@@ -0,0 +1,138 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import "fmt"
+
+// progressbar
+type ProgressBar struct {
+	BaseWidget
+}
+
+func NewProgressBar(parent Widget, orient Orient, attributes ...*WidgetAttr) *ProgressBar {
+	iid := makeNamedWidgetId(parent, "atk_progressbar")
+	attributes = append(attributes, &WidgetAttr{"orient", orient})
+	info := CreateWidgetInfo(iid, WidgetTypeProgressBar, true, attributes)
+	if info == nil {
+		return nil
+	}
+	w := &ProgressBar{}
+	w.id = iid
+	w.info = info
+	RegisterWidget(w)
+	return w
+}
+
+func (w *ProgressBar) Attach(id string) error {
+	info, err := CheckWidgetInfo(id, WidgetTypeProgressBar)
+	if err != nil {
+		return err
+	}
+	w.id = id
+	w.info = info
+	RegisterWidget(w)
+	return nil
+}
+
+func (w *ProgressBar) SetOrient(orient Orient) error {
+	return eval(fmt.Sprintf("%v configure -orient {%v}", w.id, orient))
+}
+
+func (w *ProgressBar) Orient() Orient {
+	r, err := evalAsString(fmt.Sprintf("%v cget -orient", w.id))
+	return parserOrientResult(r, err)
+}
+
+func (w *ProgressBar) SetTakeFocus(takefocus bool) error {
+	return eval(fmt.Sprintf("%v configure -takefocus {%v}", w.id, boolToInt(takefocus)))
+}
+
+func (w *ProgressBar) IsTakeFocus() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -takefocus", w.id))
+	return r
+}
+
+func (w *ProgressBar) SetLength(length int) error {
+	return eval(fmt.Sprintf("%v configure -length {%v}", w.id, length))
+}
+
+func (w *ProgressBar) Length() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -length", w.id))
+	return r
+}
+
+func (w *ProgressBar) SetMaximum(maximum float64) error {
+	return eval(fmt.Sprintf("%v configure -maximum {%v}", w.id, maximum))
+}
+
+func (w *ProgressBar) Maximum() float64 {
+	r, _ := evalAsFloat64(fmt.Sprintf("%v cget -maximum", w.id))
+	return r
+}
+
+func (w *ProgressBar) SetValue(value float64) error {
+	return eval(fmt.Sprintf("%v configure -value {%v}", w.id, value))
+}
+
+func (w *ProgressBar) Value() float64 {
+	r, _ := evalAsFloat64(fmt.Sprintf("%v cget -value", w.id))
+	return r
+}
+
+func (w *ProgressBar) Phase() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -phase", w.id))
+	return r
+}
+
+func (w *ProgressBar) SetDeterminateMode(b bool) error {
+	var mode string
+	if b {
+		mode = "determinate"
+	} else {
+		mode = "indeterminate"
+	}
+	return eval(fmt.Sprintf("%v configure -mode %v", w.id, mode))
+}
+
+func (w *ProgressBar) IsDeterminateMode() bool {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -mode", w.id))
+	return r == "determinate"
+}
+
+func (w *ProgressBar) Start() error {
+	return w.StartEx(50)
+}
+
+func (w *ProgressBar) StartEx(ms int) error {
+	return eval(fmt.Sprintf("%v start %v", w.id, ms))
+}
+
+func (w *ProgressBar) Stop() error {
+	return eval(fmt.Sprintf("%v stop", w.id))
+}
+
+func (w *ProgressBar) Pause() error {
+	cur := w.Value()
+	w.Stop()
+	return w.SetValue(cur)
+}
+
+func ProgressBarAttrOrient(orient Orient) *WidgetAttr {
+	return &WidgetAttr{"orient", orient}
+}
+
+func ProgressBarAttrTakeFocus(takefocus bool) *WidgetAttr {
+	return &WidgetAttr{"takefocus", boolToInt(takefocus)}
+}
+
+func ProgressBarAttrLength(length int) *WidgetAttr {
+	return &WidgetAttr{"length", length}
+}
+
+func ProgressBarAttrMaximum(maximum float64) *WidgetAttr {
+	return &WidgetAttr{"maximum", maximum}
+}
+
+func ProgressBarAttrValue(value float64) *WidgetAttr {
+	return &WidgetAttr{"value", value}
+}

+ 185 - 0
vendor/github.com/visualfc/atk/tk/radiobutton.go

@@ -0,0 +1,185 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import "fmt"
+
+// radio button
+type RadioButton struct {
+	BaseWidget
+	command *Command
+}
+
+func NewRadioButton(parent Widget, text string, attributes ...*WidgetAttr) *RadioButton {
+	theme := checkInitUseTheme(attributes)
+	iid := makeNamedWidgetId(parent, "atk_radiobutton")
+	attributes = append(attributes, &WidgetAttr{"text", text})
+	info := CreateWidgetInfo(iid, WidgetTypeRadioButton, theme, attributes)
+	if info == nil {
+		return nil
+	}
+	w := &RadioButton{}
+	w.id = iid
+	w.info = info
+	RegisterWidget(w)
+	return w
+}
+
+func (w *RadioButton) Attach(id string) error {
+	info, err := CheckWidgetInfo(id, WidgetTypeRadioButton)
+	if err != nil {
+		return err
+	}
+	w.id = id
+	w.info = info
+	RegisterWidget(w)
+	return nil
+}
+
+func (w *RadioButton) SetText(text string) error {
+	setObjText("atk_tmp_text", text)
+	return eval(fmt.Sprintf("%v configure -text $atk_tmp_text", w.id))
+}
+
+func (w *RadioButton) Text() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -text", w.id))
+	return r
+}
+
+func (w *RadioButton) SetWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -width {%v}", w.id, width))
+}
+
+func (w *RadioButton) Width() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -width", w.id))
+	return r
+}
+
+func (w *RadioButton) SetImage(image *Image) error {
+	if image == nil {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("%v configure -image {%v}", w.id, image.Id()))
+}
+
+func (w *RadioButton) Image() *Image {
+	r, err := evalAsString(fmt.Sprintf("%v cget -image", w.id))
+	return parserImageResult(r, err)
+}
+
+func (w *RadioButton) SetCompound(compound Compound) error {
+	return eval(fmt.Sprintf("%v configure -compound {%v}", w.id, compound))
+}
+
+func (w *RadioButton) Compound() Compound {
+	r, err := evalAsString(fmt.Sprintf("%v cget -compound", w.id))
+	return parserCompoundResult(r, err)
+}
+
+func (w *RadioButton) SetPaddingN(padx int, pady int) error {
+	if w.info.IsTtk {
+		return eval(fmt.Sprintf("%v configure -padding {%v %v}", w.id, padx, pady))
+	}
+	return eval(fmt.Sprintf("%v configure -padx {%v} -pady {%v}", w.id, padx, pady))
+}
+
+func (w *RadioButton) PaddingN() (int, int) {
+	var r string
+	var err error
+	if w.info.IsTtk {
+		r, err = evalAsString(fmt.Sprintf("%v cget -padding", w.id))
+	} else {
+		r1, _ := evalAsString(fmt.Sprintf("%v cget -padx", w.id))
+		r2, _ := evalAsString(fmt.Sprintf("%v cget -pady", w.id))
+		r = r1 + " " + r2
+	}
+	return parserPaddingResult(r, err)
+}
+
+func (w *RadioButton) SetPadding(pad Pad) error {
+	return w.SetPaddingN(pad.X, pad.Y)
+}
+
+func (w *RadioButton) Padding() Pad {
+	x, y := w.PaddingN()
+	return Pad{x, y}
+}
+
+func (w *RadioButton) SetState(state State) error {
+	return eval(fmt.Sprintf("%v configure -state {%v}", w.id, state))
+}
+
+func (w *RadioButton) State() State {
+	r, err := evalAsString(fmt.Sprintf("%v cget -state", w.id))
+	return parserStateResult(r, err)
+}
+
+func (w *RadioButton) SetTakeFocus(takefocus bool) error {
+	return eval(fmt.Sprintf("%v configure -takefocus {%v}", w.id, boolToInt(takefocus)))
+}
+
+func (w *RadioButton) IsTakeFocus() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -takefocus", w.id))
+	return r
+}
+
+func (w *RadioButton) SetChecked(check bool) *RadioButton {
+	if check {
+		eval(fmt.Sprintf("set [%v cget -variable] [%v cget -value]", w.id, w.id))
+	} else {
+		eval(fmt.Sprintf("set [%v cget -variable] {}", w.id))
+	}
+	return w
+}
+
+func (w *RadioButton) IsChecked() bool {
+	r, _ := evalAsBool(fmt.Sprintf("expr $[%v cget -variable]=={[%v cget -value]}", w.id, w.id))
+	return r
+}
+
+func (w *RadioButton) OnCommand(fn func()) error {
+	if fn == nil {
+		return ErrInvalid
+	}
+	if w.command == nil {
+		w.command = &Command{}
+		bindCommand(w.id, "command", w.command.Invoke)
+	}
+	w.command.Bind(fn)
+	return nil
+}
+
+func (w *RadioButton) Invoke() {
+	eval(fmt.Sprintf("%v invoke", w.id))
+}
+
+func RadioButtonAttrText(text string) *WidgetAttr {
+	return &WidgetAttr{"text", text}
+}
+
+func RadioButtonAttrWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"width", width}
+}
+
+func RadioButtonAttrImage(image *Image) *WidgetAttr {
+	if image == nil {
+		return nil
+	}
+	return &WidgetAttr{"image", image.Id()}
+}
+
+func RadioButtonAttrCompound(compound Compound) *WidgetAttr {
+	return &WidgetAttr{"compound", compound}
+}
+
+func RadioButtonAttrPadding(padding Pad) *WidgetAttr {
+	return &WidgetAttr{"padding", padding}
+}
+
+func RadioButtonAttrState(state State) *WidgetAttr {
+	return &WidgetAttr{"state", state}
+}
+
+func RadioButtonAttrTakeFocus(takefocus bool) *WidgetAttr {
+	return &WidgetAttr{"takefocus", boolToInt(takefocus)}
+}

+ 165 - 0
vendor/github.com/visualfc/atk/tk/radiobutton_group.go

@@ -0,0 +1,165 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+)
+
+type _RadioData struct {
+	btn   *RadioButton
+	value string
+	data  interface{}
+}
+
+type RadioGroup struct {
+	id      string
+	rds     []*_RadioData
+	command *Command
+}
+
+func NewRadioGroup() *RadioGroup {
+	id := makeNamedId("atk_radiogroup")
+	evalSetValue(id, "")
+	return &RadioGroup{id, nil, &Command{}}
+}
+
+func (w *RadioGroup) IsValid() bool {
+	return w.id != ""
+}
+
+func (w *RadioGroup) findRadio(btn *RadioButton) *_RadioData {
+	for _, rd := range w.rds {
+		if rd.btn == btn {
+			return rd
+		}
+	}
+	return nil
+}
+
+func (w *RadioGroup) findRadioByValue(value string) *_RadioData {
+	for _, rd := range w.rds {
+		if rd.value == value {
+			return rd
+		}
+	}
+	return nil
+}
+
+func (w *RadioGroup) AddNewRadio(parent Widget, text string, data interface{}, attributes ...*WidgetAttr) *RadioButton {
+	btn := NewRadioButton(parent, text, attributes...)
+	w.AddRadio(btn, data)
+	return btn
+}
+
+func (w *RadioGroup) AddRadios(btns ...*RadioButton) error {
+	for _, btn := range btns {
+		w.AddRadio(btn, nil)
+	}
+	return nil
+}
+
+func (w *RadioGroup) AddRadio(btn *RadioButton, data interface{}) error {
+	if w.findRadio(btn) != nil {
+		return ErrExist
+	}
+	if !IsValidWidget(btn) {
+		return ErrInvalid
+	}
+	value := makeNamedId("atk_radiovalue")
+	err := eval(fmt.Sprintf("%v configure -variable {%v} -value {%v}", btn.Id(), w.id, value))
+	if err != nil {
+		return err
+	}
+	w.rds = append(w.rds, &_RadioData{btn, value, data})
+	btn.OnCommand(w.command.Invoke)
+	return nil
+}
+
+func (w *RadioGroup) SetRadioData(btn *RadioButton, data interface{}) error {
+	rd := w.findRadio(btn)
+	if rd == nil {
+		return ErrNotExist
+	}
+	rd.data = data
+	return nil
+}
+
+func (w *RadioGroup) RadioList() (lst []*RadioButton) {
+	for _, v := range w.rds {
+		lst = append(lst, v.btn)
+	}
+	return
+}
+
+func (w *RadioGroup) WidgetList() (lst []Widget) {
+	for _, v := range w.rds {
+		lst = append(lst, v.btn)
+	}
+	return
+}
+
+func (w *RadioGroup) SetCheckedRadio(btn *RadioButton) error {
+	rd := w.findRadio(btn)
+	if rd == nil {
+		return ErrInvalid
+	}
+	evalSetValue(w.id, rd.value)
+	return nil
+}
+
+func (w *RadioGroup) CheckedRadio() *RadioButton {
+	s := w.checkedValue()
+	rd := w.findRadioByValue(s)
+	if rd != nil {
+		return rd.btn
+	}
+	return nil
+}
+
+func (w *RadioGroup) SetCheckedIndex(index int) error {
+	if index < 0 || index > len(w.rds) {
+		return ErrInvalid
+	}
+	evalSetValue(w.id, w.rds[index].value)
+	return nil
+}
+
+func (w *RadioGroup) CheckedIndex() int {
+	s := w.checkedValue()
+	for n, rd := range w.rds {
+		if rd.value == s {
+			return n
+		}
+	}
+	return -1
+}
+
+func (w *RadioGroup) checkedValue() string {
+	return evalGetValue(w.id)
+}
+
+func (w *RadioGroup) CheckedData() interface{} {
+	s := w.checkedValue()
+	rd := w.findRadioByValue(s)
+	if rd != nil {
+		return rd.data
+	}
+	return nil
+}
+
+func (w *RadioGroup) RadioData(btn *RadioButton) interface{} {
+	rd := w.findRadio(btn)
+	if rd == nil {
+		return nil
+	}
+	return rd.data
+}
+
+func (w *RadioGroup) OnRadioChanged(fn func()) error {
+	if fn == nil {
+		return ErrInvalid
+	}
+	w.command.Bind(fn)
+	return nil
+}

BIN
vendor/github.com/visualfc/atk/tk/rsrc_windows_386.syso


BIN
vendor/github.com/visualfc/atk/tk/rsrc_windows_amd64.syso


+ 134 - 0
vendor/github.com/visualfc/atk/tk/scale.go

@@ -0,0 +1,134 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import "fmt"
+
+// scale
+type Scale struct {
+	BaseWidget
+	command *Command
+}
+
+func NewScale(parent Widget, orient Orient, attributes ...*WidgetAttr) *Scale {
+	iid := makeNamedWidgetId(parent, "atk_separator")
+	attributes = append(attributes, &WidgetAttr{"orient", orient})
+	info := CreateWidgetInfo(iid, WidgetTypeScale, true, attributes)
+	if info == nil {
+		return nil
+	}
+	w := &Scale{}
+	w.id = iid
+	w.info = info
+	RegisterWidget(w)
+	return w
+}
+
+func (w *Scale) Attach(id string) error {
+	info, err := CheckWidgetInfo(id, WidgetTypeScale)
+	if err != nil {
+		return err
+	}
+	w.id = id
+	w.info = info
+	RegisterWidget(w)
+	return nil
+}
+
+func (w *Scale) SetOrient(orient Orient) error {
+	return eval(fmt.Sprintf("%v configure -orient {%v}", w.id, orient))
+}
+
+func (w *Scale) Orient() Orient {
+	r, err := evalAsString(fmt.Sprintf("%v cget -orient", w.id))
+	return parserOrientResult(r, err)
+}
+
+func (w *Scale) SetTakeFocus(takefocus bool) error {
+	return eval(fmt.Sprintf("%v configure -takefocus {%v}", w.id, boolToInt(takefocus)))
+}
+
+func (w *Scale) IsTakeFocus() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -takefocus", w.id))
+	return r
+}
+
+func (w *Scale) SetFrom(from float64) error {
+	return eval(fmt.Sprintf("%v configure -from {%v}", w.id, from))
+}
+
+func (w *Scale) From() float64 {
+	r, _ := evalAsFloat64(fmt.Sprintf("%v cget -from", w.id))
+	return r
+}
+
+func (w *Scale) SetTo(to float64) error {
+	return eval(fmt.Sprintf("%v configure -to {%v}", w.id, to))
+}
+
+func (w *Scale) To() float64 {
+	r, _ := evalAsFloat64(fmt.Sprintf("%v cget -to", w.id))
+	return r
+}
+
+func (w *Scale) SetValue(value float64) error {
+	return eval(fmt.Sprintf("%v configure -value {%v}", w.id, value))
+}
+
+func (w *Scale) Value() float64 {
+	r, _ := evalAsFloat64(fmt.Sprintf("%v cget -value", w.id))
+	return r
+}
+
+func (w *Scale) SetLength(length int) error {
+	return eval(fmt.Sprintf("%v configure -length {%v}", w.id, length))
+}
+
+func (w *Scale) Length() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -length", w.id))
+	return r
+}
+
+func (w *Scale) OnCommand(fn func()) error {
+	if fn == nil {
+		return ErrInvalid
+	}
+	if w.command == nil {
+		w.command = &Command{}
+		bindCommand(w.id, "command", w.command.Invoke)
+	}
+	w.command.Bind(fn)
+	return nil
+}
+
+func (w *Scale) SetRange(from, to float64) error {
+	return eval(fmt.Sprintf("%v configure -from {%v} -to {%v}", w.id, from, to))
+}
+
+func (w *Scale) Range() (float64, float64) {
+	return w.From(), w.To()
+}
+
+func ScaleAttrOrient(orient Orient) *WidgetAttr {
+	return &WidgetAttr{"orient", orient}
+}
+
+func ScaleAttrTakeFocus(takefocus bool) *WidgetAttr {
+	return &WidgetAttr{"takefocus", boolToInt(takefocus)}
+}
+
+func ScaleAttrFrom(from float64) *WidgetAttr {
+	return &WidgetAttr{"from", from}
+}
+
+func ScaleAttrTo(to float64) *WidgetAttr {
+	return &WidgetAttr{"to", to}
+}
+
+func ScaleAttrValue(value float64) *WidgetAttr {
+	return &WidgetAttr{"value", value}
+}
+
+func ScaleAttrLength(length int) *WidgetAttr {
+	return &WidgetAttr{"length", length}
+}

+ 88 - 0
vendor/github.com/visualfc/atk/tk/scrollbar.go

@@ -0,0 +1,88 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+	"strings"
+)
+
+// scrollbar
+type ScrollBar struct {
+	BaseWidget
+	command *CommandEx
+}
+
+func NewScrollBar(parent Widget, orient Orient, attributes ...*WidgetAttr) *ScrollBar {
+	theme := checkInitUseTheme(attributes)
+	iid := makeNamedWidgetId(parent, "atk_scrollbar")
+	attributes = append(attributes, &WidgetAttr{"orient", orient})
+	info := CreateWidgetInfo(iid, WidgetTypeScrollBar, theme, attributes)
+	if info == nil {
+		return nil
+	}
+	w := &ScrollBar{}
+	w.id = iid
+	w.info = info
+	RegisterWidget(w)
+	return w
+}
+
+func (w *ScrollBar) Attach(id string) error {
+	info, err := CheckWidgetInfo(id, WidgetTypeScrollBar)
+	if err != nil {
+		return err
+	}
+	w.id = id
+	w.info = info
+	RegisterWidget(w)
+	return nil
+}
+
+func (w *ScrollBar) SetOrient(orient Orient) error {
+	return eval(fmt.Sprintf("%v configure -orient {%v}", w.id, orient))
+}
+
+func (w *ScrollBar) Orient() Orient {
+	r, err := evalAsString(fmt.Sprintf("%v cget -orient", w.id))
+	return parserOrientResult(r, err)
+}
+
+func (w *ScrollBar) SetTakeFocus(takefocus bool) error {
+	return eval(fmt.Sprintf("%v configure -takefocus {%v}", w.id, boolToInt(takefocus)))
+}
+
+func (w *ScrollBar) IsTakeFocus() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -takefocus", w.id))
+	return r
+}
+
+func (w *ScrollBar) SetScroll(first float64, last float64) error {
+	err := eval(fmt.Sprintf("%v set %v %v", w.id, first, last))
+	return err
+}
+
+func (w *ScrollBar) SetScrollArgs(args []string) error {
+	err := eval(fmt.Sprintf("%v set %v", w.id, strings.Join(args, " ")))
+	return err
+}
+
+func (w *ScrollBar) OnCommandEx(fn func([]string) error) error {
+	if fn == nil {
+		return ErrInvalid
+	}
+	if w.command == nil {
+		w.command = &CommandEx{}
+		bindCommandEx(w.id, "command", w.command.Invoke)
+	}
+	w.command.Bind(fn)
+	return nil
+}
+
+func ScrollBarAttrOrient(orient Orient) *WidgetAttr {
+	return &WidgetAttr{"orient", orient}
+}
+
+func ScrollBarAttrTakeFocus(takefocus bool) *WidgetAttr {
+	return &WidgetAttr{"takefocus", boolToInt(takefocus)}
+}

+ 51 - 0
vendor/github.com/visualfc/atk/tk/scrolllayout.go

@@ -0,0 +1,51 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+type ScrollLayout struct {
+	*GridLayout
+	XScrollBar *ScrollBar
+	YScrollBar *ScrollBar
+}
+
+func NewScrollLayout(parent Widget) *ScrollLayout {
+	grid := NewGridLayout(parent)
+	xscroll := NewScrollBar(parent, Horizontal)
+	yscroll := NewScrollBar(parent, Vertical)
+	grid.AddWidget(xscroll, GridAttrRow(1), GridAttrColumn(0), GridAttrSticky(StickyEW))
+	grid.AddWidget(yscroll, GridAttrRow(0), GridAttrColumn(1), GridAttrSticky(StickyNS))
+	return &ScrollLayout{grid, xscroll, yscroll}
+}
+
+func (w *ScrollLayout) SetWidget(widget Widget) error {
+	if !IsValidWidget(widget) {
+		return ErrInvalid
+	}
+	w.AddWidget(widget, GridAttrRow(0), GridAttrColumn(0), GridAttrSticky(StickyAll))
+	w.SetRowAttr(0, 0, 1, "")
+	w.SetColumnAttr(0, 0, 1, "")
+	return nil
+}
+
+//export embedded id
+func (w *ScrollLayout) Id() string {
+	return w.id
+}
+
+func (w *ScrollLayout) ShowXScrollBar(b bool) (err error) {
+	if b {
+		err = w.AddWidget(w.XScrollBar, GridAttrRow(1), GridAttrColumn(0), GridAttrSticky(StickyEW))
+	} else {
+		err = w.RemoveWidget(w.XScrollBar)
+	}
+	return
+}
+
+func (w *ScrollLayout) ShowYScrollBar(b bool) (err error) {
+	if b {
+		err = w.AddWidget(w.YScrollBar, GridAttrRow(1), GridAttrColumn(0), GridAttrSticky(StickyEW))
+	} else {
+		err = w.RemoveWidget(w.YScrollBar)
+	}
+	return
+}

+ 61 - 0
vendor/github.com/visualfc/atk/tk/separator.go

@@ -0,0 +1,61 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import "fmt"
+
+// separator
+type Separator struct {
+	BaseWidget
+}
+
+func NewSeparator(parent Widget, orient Orient, attributes ...*WidgetAttr) *Separator {
+	iid := makeNamedWidgetId(parent, "atk_separator")
+	attributes = append(attributes, &WidgetAttr{"orient", orient})
+	info := CreateWidgetInfo(iid, WidgetTypeSeparator, true, attributes)
+	if info == nil {
+		return nil
+	}
+	w := &Separator{}
+	w.id = iid
+	w.info = info
+	RegisterWidget(w)
+	return w
+}
+
+func (w *Separator) Attach(id string) error {
+	info, err := CheckWidgetInfo(id, WidgetTypeSeparator)
+	if err != nil {
+		return err
+	}
+	w.id = id
+	w.info = info
+	RegisterWidget(w)
+	return nil
+}
+
+func (w *Separator) SetOrient(orient Orient) error {
+	return eval(fmt.Sprintf("%v configure -orient {%v}", w.id, orient))
+}
+
+func (w *Separator) Orient() Orient {
+	r, err := evalAsString(fmt.Sprintf("%v cget -orient", w.id))
+	return parserOrientResult(r, err)
+}
+
+func (w *Separator) SetTakeFocus(takefocus bool) error {
+	return eval(fmt.Sprintf("%v configure -takefocus {%v}", w.id, boolToInt(takefocus)))
+}
+
+func (w *Separator) IsTakeFocus() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -takefocus", w.id))
+	return r
+}
+
+func SeparatorAttrOrient(orient Orient) *WidgetAttr {
+	return &WidgetAttr{"orient", orient}
+}
+
+func SeparatorAttrTakeFocus(takefocus bool) *WidgetAttr {
+	return &WidgetAttr{"takefocus", boolToInt(takefocus)}
+}

+ 180 - 0
vendor/github.com/visualfc/atk/tk/spinbox.go

@@ -0,0 +1,180 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import "fmt"
+
+// spinbox
+type SpinBox struct {
+	BaseWidget
+	command        *Command
+	xscrollcommand *CommandEx
+}
+
+func NewSpinBox(parent Widget, attributes ...*WidgetAttr) *SpinBox {
+	theme := checkInitUseTheme(attributes)
+	iid := makeNamedWidgetId(parent, "atk_spinbox")
+	info := CreateWidgetInfo(iid, WidgetTypeSpinBox, theme, attributes)
+	if info == nil {
+		return nil
+	}
+	w := &SpinBox{}
+	w.id = iid
+	w.info = info
+	RegisterWidget(w)
+	return w
+}
+
+func (w *SpinBox) Attach(id string) error {
+	info, err := CheckWidgetInfo(id, WidgetTypeSpinBox)
+	if err != nil {
+		return err
+	}
+	w.id = id
+	w.info = info
+	RegisterWidget(w)
+	return nil
+}
+
+func (w *SpinBox) SetTakeFocus(takefocus bool) error {
+	return eval(fmt.Sprintf("%v configure -takefocus {%v}", w.id, boolToInt(takefocus)))
+}
+
+func (w *SpinBox) IsTakeFocus() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -takefocus", w.id))
+	return r
+}
+
+func (w *SpinBox) SetFrom(from float64) error {
+	return eval(fmt.Sprintf("%v configure -from {%v}", w.id, from))
+}
+
+func (w *SpinBox) From() float64 {
+	r, _ := evalAsFloat64(fmt.Sprintf("%v cget -from", w.id))
+	return r
+}
+
+func (w *SpinBox) SetTo(to float64) error {
+	return eval(fmt.Sprintf("%v configure -to {%v}", w.id, to))
+}
+
+func (w *SpinBox) To() float64 {
+	r, _ := evalAsFloat64(fmt.Sprintf("%v cget -to", w.id))
+	return r
+}
+
+func (w *SpinBox) SetIncrement(increment float64) error {
+	return eval(fmt.Sprintf("%v configure -increment {%v}", w.id, increment))
+}
+
+func (w *SpinBox) Increment() float64 {
+	r, _ := evalAsFloat64(fmt.Sprintf("%v cget -increment", w.id))
+	return r
+}
+
+func (w *SpinBox) SetWrap(wrap bool) error {
+	return eval(fmt.Sprintf("%v configure -wrap {%v}", w.id, boolToInt(wrap)))
+}
+
+func (w *SpinBox) IsWrap() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -wrap", w.id))
+	return r
+}
+
+func (w *SpinBox) SetTextValues(values []string) error {
+	setObjTextList("atk_tmp_textlist", values)
+	return eval(fmt.Sprintf("%v configure -values $atk_tmp_textlist", w.id))
+}
+
+func (w *SpinBox) TextValues() []string {
+	r, _ := evalAsStringList(fmt.Sprintf("%v cget -values", w.id))
+	return r
+}
+
+func (w *SpinBox) OnCommand(fn func()) error {
+	if fn == nil {
+		return ErrInvalid
+	}
+	if w.command == nil {
+		w.command = &Command{}
+		bindCommand(w.id, "command", w.command.Invoke)
+	}
+	w.command.Bind(fn)
+	return nil
+}
+
+func (w *SpinBox) OnXScrollEx(fn func([]string) error) error {
+	if fn == nil {
+		return ErrInvalid
+	}
+	if w.xscrollcommand == nil {
+		w.xscrollcommand = &CommandEx{}
+		bindCommandEx(w.id, "xscrollcommand", w.xscrollcommand.Invoke)
+	}
+	w.xscrollcommand.Bind(fn)
+	return nil
+}
+
+func (w *SpinBox) OnEditReturn(fn func()) error {
+	if fn == nil {
+		return ErrInvalid
+	}
+	w.BindEvent("<Return>", func(e *Event) {
+		fn()
+	})
+	return nil
+}
+
+func (w *SpinBox) Entry() *Entry {
+	return &Entry{w.BaseWidget, nil}
+}
+
+func (w *SpinBox) SetRange(from, to float64) error {
+	return eval(fmt.Sprintf("%v configure -from {%v} -to {%v}", w.id, from, to))
+}
+
+func (w *SpinBox) Range() (float64, float64) {
+	return w.From(), w.To()
+}
+
+func (w *SpinBox) Value() float64 {
+	r, _ := evalAsFloat64(fmt.Sprintf("%v get", w.id))
+	return r
+}
+
+func (w *SpinBox) SetValue(value float64) error {
+	return eval(fmt.Sprintf("%v set %v", w.id, value))
+}
+
+func (w *SpinBox) SetTextValue(value string) error {
+	return eval(fmt.Sprintf("%v set %v", w.id, value))
+}
+
+func (w *SpinBox) TextValue() string {
+	r, _ := evalAsString(fmt.Sprintf("%v get", w.id))
+	return r
+}
+
+func SpinBoxAttrTakeFocus(takefocus bool) *WidgetAttr {
+	return &WidgetAttr{"takefocus", boolToInt(takefocus)}
+}
+
+func SpinBoxAttrFrom(from float64) *WidgetAttr {
+	return &WidgetAttr{"from", from}
+}
+
+func SpinBoxAttrTo(to float64) *WidgetAttr {
+	return &WidgetAttr{"to", to}
+}
+
+func SpinBoxAttrIncrement(increment float64) *WidgetAttr {
+	return &WidgetAttr{"increment", increment}
+}
+
+func SpinBoxAttrWrap(wrap bool) *WidgetAttr {
+	return &WidgetAttr{"wrap", boolToInt(wrap)}
+}
+
+func SpinBoxAttrTextValues(values []string) *WidgetAttr {
+	return &WidgetAttr{"values", values}
+}

+ 631 - 0
vendor/github.com/visualfc/atk/tk/text.go

@@ -0,0 +1,631 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+	"strings"
+)
+
+// Create and manipulate 'text' hypertext editing widgets
+type Text struct {
+	BaseWidget
+	xscrollcommand *CommandEx
+	yscrollcommand *CommandEx
+}
+
+func NewText(parent Widget, attributes ...*WidgetAttr) *Text {
+	theme := checkInitUseTheme(attributes)
+	iid := makeNamedWidgetId(parent, "atk_text")
+	info := CreateWidgetInfo(iid, WidgetTypeText, theme, attributes)
+	if info == nil {
+		return nil
+	}
+	w := &Text{}
+	w.id = iid
+	w.info = info
+	RegisterWidget(w)
+	return w
+}
+
+func (w *Text) Attach(id string) error {
+	info, err := CheckWidgetInfo(id, WidgetTypeText)
+	if err != nil {
+		return err
+	}
+	w.id = id
+	w.info = info
+	RegisterWidget(w)
+	return nil
+}
+
+func (w *Text) SetBackground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -background $atk_tmp_text", w.id))
+}
+
+func (w *Text) Background() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -background", w.id))
+	return r
+}
+
+func (w *Text) SetBorderWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -borderwidth {%v}", w.id, width))
+}
+
+func (w *Text) BorderWidth() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -borderwidth", w.id))
+	return r
+}
+
+func (w *Text) SetFont(font Font) error {
+	if font == nil {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("%v configure -font {%v}", w.id, font.Id()))
+}
+
+func (w *Text) Font() Font {
+	r, err := evalAsString(fmt.Sprintf("%v cget -font", w.id))
+	return parserFontResult(r, err)
+}
+
+func (w *Text) SetForeground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -foreground $atk_tmp_text", w.id))
+}
+
+func (w *Text) Foreground() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -foreground", w.id))
+	return r
+}
+
+func (w *Text) SetHighlightBackground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -highlightbackground $atk_tmp_text", w.id))
+}
+
+func (w *Text) HighlightBackground() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -highlightbackground", w.id))
+	return r
+}
+
+func (w *Text) SetHighlightColor(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -highlightcolor $atk_tmp_text", w.id))
+}
+
+func (w *Text) HighlightColor() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -highlightcolor", w.id))
+	return r
+}
+
+func (w *Text) SetHighlightthickness(width int) error {
+	return eval(fmt.Sprintf("%v configure -highlightthickness {%v}", w.id, width))
+}
+
+func (w *Text) Highlightthickness() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -highlightthickness", w.id))
+	return r
+}
+
+func (w *Text) SetInsertBackground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -insertbackground $atk_tmp_text", w.id))
+}
+
+func (w *Text) InsertBackground() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -insertbackground", w.id))
+	return r
+}
+
+func (w *Text) SetInsertBorderWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -insertborderwidth {%v}", w.id, width))
+}
+
+func (w *Text) InsertBorderWidth() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -insertborderwidth", w.id))
+	return r
+}
+
+func (w *Text) SetInsertOffTime(offtime int) error {
+	return eval(fmt.Sprintf("%v configure -insertofftime {%v}", w.id, offtime))
+}
+
+func (w *Text) InsertOffTime() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -insertofftime", w.id))
+	return r
+}
+
+func (w *Text) SetInsertOnTime(ontime int) error {
+	return eval(fmt.Sprintf("%v configure -insertontime {%v}", w.id, ontime))
+}
+
+func (w *Text) InsertOnTime() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -insertontime", w.id))
+	return r
+}
+
+func (w *Text) SetInsertWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -insertwidth {%v}", w.id, width))
+}
+
+func (w *Text) InsertWidth() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -insertwidth", w.id))
+	return r
+}
+
+func (w *Text) SetPaddingN(padx int, pady int) error {
+	if w.info.IsTtk {
+		return eval(fmt.Sprintf("%v configure -padding {%v %v}", w.id, padx, pady))
+	}
+	return eval(fmt.Sprintf("%v configure -padx {%v} -pady {%v}", w.id, padx, pady))
+}
+
+func (w *Text) PaddingN() (int, int) {
+	var r string
+	var err error
+	if w.info.IsTtk {
+		r, err = evalAsString(fmt.Sprintf("%v cget -padding", w.id))
+	} else {
+		r1, _ := evalAsString(fmt.Sprintf("%v cget -padx", w.id))
+		r2, _ := evalAsString(fmt.Sprintf("%v cget -pady", w.id))
+		r = r1 + " " + r2
+	}
+	return parserPaddingResult(r, err)
+}
+
+func (w *Text) SetPadding(pad Pad) error {
+	return w.SetPaddingN(pad.X, pad.Y)
+}
+
+func (w *Text) Padding() Pad {
+	x, y := w.PaddingN()
+	return Pad{x, y}
+}
+
+func (w *Text) SetReliefStyle(relief ReliefStyle) error {
+	return eval(fmt.Sprintf("%v configure -relief {%v}", w.id, relief))
+}
+
+func (w *Text) ReliefStyle() ReliefStyle {
+	r, err := evalAsString(fmt.Sprintf("%v cget -relief", w.id))
+	return parserReliefStyleResult(r, err)
+}
+
+func (w *Text) SetSelectBackground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -selectbackground $atk_tmp_text", w.id))
+}
+
+func (w *Text) SelectBackground() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -selectbackground", w.id))
+	return r
+}
+
+func (w *Text) SetSelectborderwidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -selectborderwidth {%v}", w.id, width))
+}
+
+func (w *Text) Selectborderwidth() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -selectborderwidth", w.id))
+	return r
+}
+
+func (w *Text) SetSelectforeground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -selectforeground $atk_tmp_text", w.id))
+}
+
+func (w *Text) Selectforeground() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -selectforeground", w.id))
+	return r
+}
+
+func (w *Text) SetInactiveSelectBackground(color string) error {
+	setObjText("atk_tmp_text", color)
+	return eval(fmt.Sprintf("%v configure -inactiveselectbackground $atk_tmp_text", w.id))
+}
+
+func (w *Text) InactiveSelectBackground() string {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -inactiveselectbackground", w.id))
+	return r
+}
+
+func (w *Text) SetTakeFocus(takefocus bool) error {
+	return eval(fmt.Sprintf("%v configure -takefocus {%v}", w.id, boolToInt(takefocus)))
+}
+
+func (w *Text) IsTakeFocus() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -takefocus", w.id))
+	return r
+}
+
+func (w *Text) SetAutoSeparatorsOnUndo(autoseparators bool) error {
+	return eval(fmt.Sprintf("%v configure -autoseparators {%v}", w.id, boolToInt(autoseparators)))
+}
+
+func (w *Text) IsAutoSeparatorsOnUndo() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -autoseparators", w.id))
+	return r
+}
+
+func (w *Text) SetBlockCursor(blockcursor bool) error {
+	return eval(fmt.Sprintf("%v configure -blockcursor {%v}", w.id, boolToInt(blockcursor)))
+}
+
+func (w *Text) IsBlockCursor() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -blockcursor", w.id))
+	return r
+}
+
+func (w *Text) SetStartLine(startline int) error {
+	return eval(fmt.Sprintf("%v configure -startline {%v}", w.id, startline))
+}
+
+func (w *Text) StartLine() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -startline", w.id))
+	return r
+}
+
+func (w *Text) SetEndLine(endline int) error {
+	return eval(fmt.Sprintf("%v configure -endline {%v}", w.id, endline))
+}
+
+func (w *Text) EndLine() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -endline", w.id))
+	return r
+}
+
+func (w *Text) SetWidth(width int) error {
+	return eval(fmt.Sprintf("%v configure -width {%v}", w.id, width))
+}
+
+func (w *Text) Width() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -width", w.id))
+	return r
+}
+
+func (w *Text) SetHeight(height int) error {
+	return eval(fmt.Sprintf("%v configure -height {%v}", w.id, height))
+}
+
+func (w *Text) Height() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -height", w.id))
+	return r
+}
+
+func (w *Text) SetInsertUnfocussed(style DisplyCursor) error {
+	if !mainInterp.SupportTk86() {
+		return ErrUnsupport
+	}
+	return eval(fmt.Sprintf("%v configure -insertunfocussed {%v}", w.id, style))
+}
+
+func (w *Text) InsertUnfocussed() DisplyCursor {
+	if !mainInterp.SupportTk86() {
+		return DisplyCursorHollow
+	}
+	r, err := evalAsString(fmt.Sprintf("%v cget -insertunfocussed", w.id))
+	return parserDisplyCursorResult(r, err)
+}
+
+func (w *Text) SetMaxUndo(maxundo int) error {
+	return eval(fmt.Sprintf("%v configure -maxundo {%v}", w.id, maxundo))
+}
+
+func (w *Text) MaxUndo() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -maxundo", w.id))
+	return r
+}
+
+func (w *Text) SetLineAboveSpace(spacing int) error {
+	return eval(fmt.Sprintf("%v configure -spacing1 {%v}", w.id, spacing))
+}
+
+func (w *Text) LineAboveSpace() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -spacing1", w.id))
+	return r
+}
+
+func (w *Text) SetLineWrapSpace(spacing int) error {
+	return eval(fmt.Sprintf("%v configure -spacing2 {%v}", w.id, spacing))
+}
+
+func (w *Text) LineWrapSpace() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -spacing2", w.id))
+	return r
+}
+
+func (w *Text) SetLineBelowSpace(spacing int) error {
+	return eval(fmt.Sprintf("%v configure -spacing3 {%v}", w.id, spacing))
+}
+
+func (w *Text) LineBelowSpace() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -spacing3", w.id))
+	return r
+}
+
+func (w *Text) SetLineWrap(wrap LineWrapMode) error {
+	return eval(fmt.Sprintf("%v configure -wrap {%v}", w.id, wrap))
+}
+
+func (w *Text) LineWrap() LineWrapMode {
+	r, err := evalAsString(fmt.Sprintf("%v cget -wrap", w.id))
+	return parserLineWrapModeResult(r, err)
+}
+
+func (w *Text) SetEnableUndo(undo bool) error {
+	return eval(fmt.Sprintf("%v configure -undo {%v}", w.id, boolToInt(undo)))
+}
+
+func (w *Text) IsEnableUndo() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -undo", w.id))
+	return r
+}
+
+func (w *Text) SetReadOnly(b bool) error {
+	var script string
+	if b {
+		script = fmt.Sprintf("%v configure -state disable", w.id)
+	} else {
+		script = fmt.Sprintf("%v configure -state normal", w.id)
+	}
+	return eval(script)
+}
+
+func (w *Text) IsReadOnly() bool {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -state", w.id))
+	return r != "normal"
+}
+
+type TextIndex struct {
+	index string
+}
+
+func (t TextIndex) String() string {
+	return t.index
+}
+
+func (w *Text) TextLength() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v count -chars 1.0 end", w.id))
+	return r
+}
+
+func (w *Text) PlainText() string {
+	r, _ := evalAsString(fmt.Sprintf("%v get 1.0 end", w.id))
+	return r
+}
+
+func (w *Text) LineCount() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v count -lines 1.0 end", w.id))
+	return r
+}
+
+func (w *Text) InsertText(pos int, text string) error {
+	setObjText("atk_text_insert", text)
+	return eval(fmt.Sprintf("%v insert {0.0 + %v chars} $atk_text_insert", w.id, pos))
+}
+
+func (w *Text) AppendText(text string) error {
+	setObjText("atk_text_insert", text)
+	return eval(fmt.Sprintf("%v insert end $atk_text_insert", w.id))
+}
+
+func (w *Text) Length() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v index end", w.id))
+	return r
+}
+
+func (w *Text) Clear() error {
+	return eval(fmt.Sprintf("%v delete 1.0 end", w.id))
+}
+
+func (w *Text) SetText(text string) error {
+	setObjText("atk_text_insert", text)
+	return eval(fmt.Sprintf("%v delete 1.0 end\n%v insert end $atk_text_insert", w.id, w.id))
+}
+
+func (w *Text) SetTabSize(size int) error {
+	return eval(fmt.Sprintf("%v configure -tabs %v", w.id, size))
+}
+
+func (w *Text) SetXViewArgs(args []string) error {
+	return eval(fmt.Sprintf("%v xview %v", w.id, strings.Join(args, " ")))
+}
+
+func (w *Text) SetYViewArgs(args []string) error {
+	return eval(fmt.Sprintf("%v yview %v", w.id, strings.Join(args, " ")))
+}
+
+func (w *Text) OnXScrollEx(fn func([]string) error) error {
+	if fn == nil {
+		return ErrInvalid
+	}
+	if w.xscrollcommand == nil {
+		w.xscrollcommand = &CommandEx{}
+		bindCommandEx(w.id, "xscrollcommand", w.xscrollcommand.Invoke)
+	}
+	w.xscrollcommand.Bind(fn)
+	return nil
+}
+
+func (w *Text) OnYScrollEx(fn func([]string) error) error {
+	if fn == nil {
+		return ErrInvalid
+	}
+	if w.yscrollcommand == nil {
+		w.yscrollcommand = &CommandEx{}
+		bindCommandEx(w.id, "yscrollcommand", w.yscrollcommand.Invoke)
+	}
+	w.yscrollcommand.Bind(fn)
+	return nil
+}
+
+func (w *Text) BindXScrollBar(bar *ScrollBar) error {
+	if !IsValidWidget(bar) {
+		return ErrInvalid
+	}
+	w.OnXScrollEx(bar.SetScrollArgs)
+	bar.OnCommandEx(w.SetXViewArgs)
+	return nil
+}
+
+func (w *Text) BindYScrollBar(bar *ScrollBar) error {
+	if !IsValidWidget(bar) {
+		return ErrInvalid
+	}
+	w.OnYScrollEx(bar.SetScrollArgs)
+	bar.OnCommandEx(w.SetYViewArgs)
+	return nil
+}
+
+type TextEx struct {
+	*ScrollLayout
+	*Text
+}
+
+func NewTextEx(parent Widget, attributs ...*WidgetAttr) *TextEx {
+	w := &TextEx{}
+	w.ScrollLayout = NewScrollLayout(parent)
+	w.Text = NewText(parent, attributs...)
+	w.SetWidget(w.Text)
+	w.Text.BindXScrollBar(w.XScrollBar)
+	w.Text.BindYScrollBar(w.YScrollBar)
+	RegisterWidget(w)
+	return w
+}
+
+func TextAttrBackground(color string) *WidgetAttr {
+	return &WidgetAttr{"background", color}
+}
+
+func TextAttrBorderWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"borderwidth", width}
+}
+
+func TextAttrFont(font Font) *WidgetAttr {
+	if font == nil {
+		return nil
+	}
+	return &WidgetAttr{"font", font.Id()}
+}
+
+func TextAttrForeground(color string) *WidgetAttr {
+	return &WidgetAttr{"foreground", color}
+}
+
+func TextAttrHighlightBackground(color string) *WidgetAttr {
+	return &WidgetAttr{"highlightbackground", color}
+}
+
+func TextAttrHighlightColor(color string) *WidgetAttr {
+	return &WidgetAttr{"highlightcolor", color}
+}
+
+func TextAttrHighlightthickness(width int) *WidgetAttr {
+	return &WidgetAttr{"highlightthickness", width}
+}
+
+func TextAttrInsertBackground(color string) *WidgetAttr {
+	return &WidgetAttr{"insertbackground", color}
+}
+
+func TextAttrInsertBorderWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"insertborderwidth", width}
+}
+
+func TextAttrInsertOffTime(offtime int) *WidgetAttr {
+	return &WidgetAttr{"insertofftime", offtime}
+}
+
+func TextAttrInsertOnTime(ontime int) *WidgetAttr {
+	return &WidgetAttr{"insertontime", ontime}
+}
+
+func TextAttrInsertWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"insertwidth", width}
+}
+
+func TextAttrPadding(padding Pad) *WidgetAttr {
+	return &WidgetAttr{"padding", padding}
+}
+
+func TextAttrReliefStyle(relief ReliefStyle) *WidgetAttr {
+	return &WidgetAttr{"relief", relief}
+}
+
+func TextAttrSelectBackground(color string) *WidgetAttr {
+	return &WidgetAttr{"selectbackground", color}
+}
+
+func TextAttrSelectborderwidth(width int) *WidgetAttr {
+	return &WidgetAttr{"selectborderwidth", width}
+}
+
+func TextAttrSelectforeground(color string) *WidgetAttr {
+	return &WidgetAttr{"selectforeground", color}
+}
+
+func TextAttrInactiveSelectBackground(color string) *WidgetAttr {
+	return &WidgetAttr{"inactiveselectbackground", color}
+}
+
+func TextAttrTakeFocus(takefocus bool) *WidgetAttr {
+	return &WidgetAttr{"takefocus", boolToInt(takefocus)}
+}
+
+func TextAttrAutoSeparatorsOnUndo(autoseparators bool) *WidgetAttr {
+	return &WidgetAttr{"autoseparators", boolToInt(autoseparators)}
+}
+
+func TextAttrBlockCursor(blockcursor bool) *WidgetAttr {
+	return &WidgetAttr{"blockcursor", boolToInt(blockcursor)}
+}
+
+func TextAttrStartLine(startline int) *WidgetAttr {
+	return &WidgetAttr{"startline", startline}
+}
+
+func TextAttrEndLine(endline int) *WidgetAttr {
+	return &WidgetAttr{"endline", endline}
+}
+
+func TextAttrWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"width", width}
+}
+
+func TextAttrHeight(height int) *WidgetAttr {
+	return &WidgetAttr{"height", height}
+}
+
+func TextAttrInsertUnfocussed(style DisplyCursor) *WidgetAttr {
+	if !mainInterp.SupportTk86() {
+		return nil
+	}
+	return &WidgetAttr{"insertunfocussed", style}
+}
+
+func TextAttrMaxUndo(maxundo int) *WidgetAttr {
+	return &WidgetAttr{"maxundo", maxundo}
+}
+
+func TextAttrLineAboveSpace(spacing int) *WidgetAttr {
+	return &WidgetAttr{"spacing1", spacing}
+}
+
+func TextAttrLineWrapSpace(spacing int) *WidgetAttr {
+	return &WidgetAttr{"spacing2", spacing}
+}
+
+func TextAttrLineBelowSpace(spacing int) *WidgetAttr {
+	return &WidgetAttr{"spacing3", spacing}
+}
+
+func TextAttrLineWrap(wrap LineWrapMode) *WidgetAttr {
+	return &WidgetAttr{"wrap", wrap}
+}
+
+func TextAttrEnableUndo(undo bool) *WidgetAttr {
+	return &WidgetAttr{"undo", boolToInt(undo)}
+}

+ 30 - 0
vendor/github.com/visualfc/atk/tk/theme.go

@@ -0,0 +1,30 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+type NativeAttr struct {
+	Key   string
+	Value string
+}
+
+type Theme interface {
+	Name() string
+	IsTtk() bool
+	InitAttributes(typ WidgetType) []NativeAttr
+}
+
+func SetMainTheme(theme Theme) {
+	mainTheme = theme
+}
+
+func MainTheme() Theme {
+	return mainTheme
+}
+
+func HasTheme() bool {
+	return mainTheme != nil
+}
+
+var (
+	mainTheme Theme
+)

+ 55 - 0
vendor/github.com/visualfc/atk/tk/theme_ttk.go

@@ -0,0 +1,55 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+)
+
+type ttkTheme struct {
+}
+
+func (t *ttkTheme) Name() string {
+	return "ttk theme"
+}
+
+func (t *ttkTheme) IsTtk() bool {
+	return true
+}
+
+func (t *ttkTheme) InitAttributes(typ WidgetType) []NativeAttr {
+	return nil
+}
+
+func (t *ttkTheme) ThemeIdList() []string {
+	return ttk_theme_list
+}
+
+func (t *ttkTheme) SetThemeId(id string) error {
+	for _, v := range ttk_theme_list {
+		if v == id {
+			err := eval(fmt.Sprintf("ttk::setTheme %v", id))
+			return err
+		}
+	}
+	err := fmt.Errorf("not found ttk_theme id:%v", id)
+	dumpError(err)
+	return err
+}
+
+func (t *ttkTheme) ThemeId() string {
+	r, _ := evalAsString("ttk::style theme use")
+	return r
+}
+
+var (
+	ttk_theme_list []string
+	TtkTheme       = &ttkTheme{}
+)
+
+func init() {
+	registerInit(func() {
+		ttk_theme_list, _ = evalAsStringList("ttk::themes")
+	})
+	SetMainTheme(TtkTheme)
+}

+ 266 - 0
vendor/github.com/visualfc/atk/tk/tk.go

@@ -0,0 +1,266 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+	"log"
+	"runtime"
+
+	"github.com/visualfc/atk/tk/interp"
+)
+
+var (
+	tkHasInit            bool
+	tkWindowInitAutoHide bool
+	mainInterp           *interp.Interp
+	rootWindow           *Window
+	fnErrorHandle        func(error) = func(err error) {
+		log.Println(err)
+	}
+)
+
+func Init() error {
+	return InitEx(true, "", "")
+}
+
+func InitEx(tk_window_init_hide bool, tcl_library string, tk_library string) (err error) {
+	mainInterp, err = interp.NewInterp()
+	if err != nil {
+		dumpError(err)
+		return err
+	}
+	err = mainInterp.InitTcl(tcl_library)
+	if err != nil {
+		dumpError(err)
+		return err
+	}
+	err = mainInterp.InitTk(tk_library)
+	if err != nil {
+		dumpError(err)
+		return err
+	}
+
+	tkWindowInitAutoHide = tk_window_init_hide
+	//hide console for macOS bundle
+	mainInterp.Eval("if {[info commands console] == \"console\"} {console hide}")
+
+	for _, fn := range init_func_list {
+		fn()
+	}
+	rootWindow = &Window{}
+	rootWindow.Attach(".")
+	if tkWindowInitAutoHide {
+		rootWindow.Hide()
+	}
+	//hide wish menu on macos
+	rootWindow.SetMenu(NewMenu(nil))
+	tkHasInit = true
+	return nil
+}
+
+var (
+	init_func_list []func()
+)
+
+func registerInit(fn func()) {
+	init_func_list = append(init_func_list, fn)
+}
+
+func SetErrorHandle(fn func(error)) {
+	fnErrorHandle = fn
+}
+
+func MainInterp() *interp.Interp {
+	return mainInterp
+}
+
+func TclVersion() (ver string) {
+	return mainInterp.TclVersion()
+}
+
+func TkVersion() (ver string) {
+	return mainInterp.TkVersion()
+}
+
+func TclLibary() (path string) {
+	path, _ = evalAsString("set tcl_library")
+	return
+}
+
+func TkLibrary() (path string) {
+	path, _ = evalAsString("set tk_library")
+	return
+}
+
+func init() {
+	runtime.LockOSThread()
+}
+
+func MainLoop(fn func()) error {
+	if !tkHasInit {
+		err := Init()
+		if err != nil {
+			dumpError(err)
+			return err
+		}
+	}
+	interp.MainLoop(fn)
+	return nil
+}
+
+func Async(fn func()) {
+	interp.Async(fn)
+}
+
+func Update() {
+	eval("update")
+}
+
+func Quit() {
+	Async(func() {
+		DestroyWidget(rootWindow)
+	})
+}
+
+func eval(script string) error {
+	err := mainInterp.Eval(script)
+	if err != nil {
+		dumpError(fmt.Errorf("script: %q, error: %q", script, err))
+	}
+	return err
+}
+
+func evalEx(script string, dump bool) error {
+	err := mainInterp.Eval(script)
+	if dump && err != nil {
+		dumpError(err)
+	}
+	return err
+}
+
+func evalAsString(script string) (string, error) {
+	r, err := mainInterp.EvalAsString(script)
+	if err != nil {
+		dumpError(err)
+	}
+	return r, err
+}
+
+func evalAsStringEx(script string, dump bool) (string, error) {
+	r, err := mainInterp.EvalAsString(script)
+	if dump && err != nil {
+		dumpError(err)
+	}
+	return r, err
+}
+
+func evalAsInt(script string) (int, error) {
+	r, err := mainInterp.EvalAsInt(script)
+	if err != nil {
+		dumpError(err)
+	}
+	return r, err
+}
+
+func evalAsIntEx(script string, dump bool) (int, error) {
+	r, err := mainInterp.EvalAsInt(script)
+	if dump && err != nil {
+		dumpError(err)
+	}
+	return r, err
+}
+
+func evalAsUint(script string) (uint, error) {
+	r, err := mainInterp.EvalAsUint(script)
+	if err != nil {
+		dumpError(err)
+	}
+	return r, err
+}
+
+func evalAsUintEx(script string, dump bool) (uint, error) {
+	r, err := mainInterp.EvalAsUint(script)
+	if dump && err != nil {
+		dumpError(err)
+	}
+	return r, err
+}
+
+func evalAsFloat64(script string) (float64, error) {
+	r, err := mainInterp.EvalAsFloat64(script)
+	if err != nil {
+		dumpError(err)
+	}
+	return r, err
+}
+
+func evalAsFloat64Ex(script string, dump bool) (float64, error) {
+	r, err := mainInterp.EvalAsFloat64(script)
+	if dump && err != nil {
+		dumpError(err)
+	}
+	return r, err
+}
+
+func evalAsBool(script string) (bool, error) {
+	r, err := mainInterp.EvalAsBool(script)
+	if err != nil {
+		dumpError(err)
+	}
+	return r, err
+}
+
+func evalAsBoolEx(script string, dump bool) (bool, error) {
+	r, err := mainInterp.EvalAsBool(script)
+	if dump && err != nil {
+		dumpError(err)
+	}
+	return r, err
+}
+
+func evalAsStringList(script string) ([]string, error) {
+	r, err := mainInterp.EvalAsStringList(script)
+	if err != nil {
+		dumpError(err)
+	}
+	return r, err
+}
+
+func evalAsStringListEx(script string, dump bool) ([]string, error) {
+	r, err := mainInterp.EvalAsStringList(script)
+	if dump && err != nil {
+		dumpError(err)
+	}
+	return r, err
+}
+
+func evalAsIntList(script string) ([]int, error) {
+	r, err := mainInterp.EvalAsIntList(script)
+	if err != nil {
+		dumpError(err)
+	}
+	return r, err
+}
+
+func evalAsIntListEx(script string, dump bool) ([]int, error) {
+	r, err := mainInterp.EvalAsIntList(script)
+	if dump && err != nil {
+		dumpError(err)
+	}
+	return r, err
+}
+
+func dumpError(err error) {
+	if fnErrorHandle != nil {
+		fnErrorHandle(fmt.Errorf("%v", err))
+	}
+}
+
+func setObjText(obj string, text string) {
+	mainInterp.SetStringVar(obj, text, false)
+}
+
+func setObjTextList(obj string, list []string) {
+	mainInterp.SetStringList(obj, list, false)
+}

+ 17 - 0
vendor/github.com/visualfc/atk/tk/tk.manifest

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly
+    xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"
+    xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
+    <assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="atk" type="win32"/>
+    <dependency>
+        <dependentAssembly>
+            <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>
+        </dependentAssembly>
+    </dependency>
+    <asmv3:application>
+        <asmv3:windowsSettings
+            xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
+            <dpiAware>true</dpiAware>
+        </asmv3:windowsSettings>
+    </asmv3:application>
+</assembly>

+ 211 - 0
vendor/github.com/visualfc/atk/tk/treeitem.go

@@ -0,0 +1,211 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import "fmt"
+
+type TreeItem struct {
+	tree *TreeView
+	id   string
+}
+
+func (t *TreeItem) Id() string {
+	return t.id
+}
+
+func (t *TreeItem) IsValid() bool {
+	return t != nil && t.tree != nil
+}
+
+func (t *TreeItem) InsertItem(index int, text string, values []string) *TreeItem {
+	if !t.IsValid() {
+		return nil
+	}
+	return t.tree.InsertItem(t, index, text, values)
+}
+
+func (t *TreeItem) Index() int {
+	if !t.IsValid() || t.IsRoot() {
+		return -1
+	}
+	r, err := evalAsIntEx(fmt.Sprintf("%v index {%v}", t.tree.id, t.id), false)
+	if err != nil {
+		return -1
+	}
+	return r
+}
+
+func (t *TreeItem) IsRoot() bool {
+	return t.id == ""
+}
+
+func (t *TreeItem) Parent() *TreeItem {
+	if !t.IsValid() || t.IsRoot() {
+		return nil
+	}
+	r, err := evalAsStringEx(fmt.Sprintf("%v parent {%v}", t.tree.id, t.id), false)
+	if err != nil {
+		return nil
+	}
+	return &TreeItem{t.tree, r}
+}
+
+func (t *TreeItem) Next() *TreeItem {
+	if !t.IsValid() || t.IsRoot() {
+		return nil
+	}
+	r, err := evalAsStringEx(fmt.Sprintf("%v next {%v}", t.tree.id, t.id), false)
+	if err != nil || r == "" {
+		return nil
+	}
+	return &TreeItem{t.tree, r}
+}
+
+func (t *TreeItem) Prev() *TreeItem {
+	if !t.IsValid() || t.IsRoot() {
+		return nil
+	}
+	r, err := evalAsStringEx(fmt.Sprintf("%v prev {%v}", t.tree.id, t.id), false)
+	if err != nil || r == "" {
+		return nil
+	}
+	return &TreeItem{t.tree, r}
+}
+
+func (t *TreeItem) Children() (lst []*TreeItem) {
+	if !t.IsValid() {
+		return
+	}
+	ids, err := evalAsStringList(fmt.Sprintf("%v children {%v}", t.tree.id, t.id))
+	if err != nil {
+		return
+	}
+	for _, id := range ids {
+		lst = append(lst, &TreeItem{t.tree, id})
+	}
+	return
+}
+
+func (t *TreeItem) SetExpanded(expand bool) error {
+	if !t.IsValid() || t.IsRoot() {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("%v item {%v} -open %v", t.tree.id, t.id, expand))
+}
+
+func (t *TreeItem) IsExpanded() bool {
+	if !t.IsValid() || t.IsRoot() {
+		return false
+	}
+	r, _ := evalAsBool(fmt.Sprintf("%v item {%v} -open", t.tree.id, t.id))
+	return r
+}
+
+func (t *TreeItem) expandAll(item *TreeItem) error {
+	for _, child := range item.Children() {
+		child.SetExpanded(true)
+		t.expandAll(child)
+	}
+	return nil
+}
+
+func (t *TreeItem) ExpandAll() error {
+	return t.expandAll(t)
+}
+
+func (t *TreeItem) collapseAll(item *TreeItem) error {
+	for _, child := range item.Children() {
+		child.SetExpanded(false)
+		t.collapseAll(child)
+	}
+	return nil
+}
+
+func (t *TreeItem) CollapseAll() error {
+	return t.collapseAll(t)
+}
+
+func (t *TreeItem) Expand() error {
+	return t.SetExpanded(true)
+}
+
+func (t *TreeItem) Collapse() error {
+	return t.SetExpanded(false)
+}
+
+func (t *TreeItem) SetText(text string) error {
+	if !t.IsValid() || t.IsRoot() {
+		return ErrInvalid
+	}
+	setObjText("atk_tree_item", text)
+	return eval(fmt.Sprintf("%v item {%v} -text $atk_tree_item", t.tree.id, t.id))
+}
+
+func (t *TreeItem) Text() string {
+	if !t.IsValid() || t.IsRoot() {
+		return ""
+	}
+	r, _ := evalAsString(fmt.Sprintf("%v item {%v} -text", t.tree.id, t.id))
+	return r
+}
+
+func (t *TreeItem) SetValues(values []string) error {
+	if !t.IsValid() || t.IsRoot() {
+		return ErrInvalid
+	}
+	setObjTextList("atk_tree_values", values)
+	return eval(fmt.Sprintf("%v item {%v} -values $atk_tree_values", t.tree.id, t.id))
+}
+
+func (t *TreeItem) Values() []string {
+	if !t.IsValid() || t.IsRoot() {
+		return nil
+	}
+	r, _ := evalAsStringList(fmt.Sprintf("%v item {%v} -values", t.tree.id, t.id))
+	return r
+}
+
+func (t *TreeItem) SetImage(img *Image) error {
+	if !t.IsValid() || t.IsRoot() {
+		return ErrInvalid
+	}
+	var iid string
+	if img != nil {
+		iid = img.Id()
+	}
+	return eval(fmt.Sprintf("%v item {%v} -image {%v}", t.tree.id, t.id, iid))
+}
+
+func (t *TreeItem) Image() *Image {
+	if !t.IsValid() || t.IsRoot() {
+		return nil
+	}
+	r, err := evalAsString(fmt.Sprintf("%v item {%v} -image", t.tree.id, t.id))
+	return parserImageResult(r, err)
+}
+
+func (t *TreeItem) SetColumnText(column int, text string) error {
+	if column < 0 {
+		return ErrInvalid
+	} else if column == 0 {
+		return t.SetText(text)
+	}
+	if !t.IsValid() || t.IsRoot() {
+		return ErrInvalid
+	}
+	setObjText("atk_tree_column", text)
+	return eval(fmt.Sprintf("%v set {%v} %v $atk_tree_column", t.tree.id, t.id, column-1))
+}
+
+func (t *TreeItem) ColumnText(column int) string {
+	if column < 0 {
+		return ""
+	} else if column == 0 {
+		return t.Text()
+	}
+	if !t.IsValid() || t.IsRoot() {
+		return ""
+	}
+	r, _ := evalAsString(fmt.Sprintf("%v set {%v} %v", t.tree.id, t.id, column-1))
+	return r
+}

+ 557 - 0
vendor/github.com/visualfc/atk/tk/treeview.go

@@ -0,0 +1,557 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+	"strings"
+)
+
+// treeview
+type TreeView struct {
+	BaseWidget
+	xscrollcommand *CommandEx
+	yscrollcommand *CommandEx
+}
+
+func NewTreeView(parent Widget, attributes ...*WidgetAttr) *TreeView {
+	theme := checkInitUseTheme(attributes)
+	iid := makeNamedWidgetId(parent, "atk_treeview")
+	info := CreateWidgetInfo(iid, WidgetTypeTreeView, theme, attributes)
+	if info == nil {
+		return nil
+	}
+	w := &TreeView{}
+	w.id = iid
+	w.info = info
+	RegisterWidget(w)
+	return w
+}
+
+func (w *TreeView) Attach(id string) error {
+	info, err := CheckWidgetInfo(id, WidgetTypeTreeView)
+	if err != nil {
+		return err
+	}
+	w.id = id
+	w.info = info
+	RegisterWidget(w)
+	return nil
+}
+
+func (w *TreeView) SetTakeFocus(takefocus bool) error {
+	return eval(fmt.Sprintf("%v configure -takefocus {%v}", w.id, boolToInt(takefocus)))
+}
+
+func (w *TreeView) IsTakeFocus() bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v cget -takefocus", w.id))
+	return r
+}
+
+func (w *TreeView) SetHeight(row int) error {
+	return eval(fmt.Sprintf("%v configure -height {%v}", w.id, row))
+}
+
+func (w *TreeView) Height() int {
+	r, _ := evalAsInt(fmt.Sprintf("%v cget -height", w.id))
+	return r
+}
+
+func (w *TreeView) SetPaddingN(padx int, pady int) error {
+	if w.info.IsTtk {
+		return eval(fmt.Sprintf("%v configure -padding {%v %v}", w.id, padx, pady))
+	}
+	return eval(fmt.Sprintf("%v configure -padx {%v} -pady {%v}", w.id, padx, pady))
+}
+
+func (w *TreeView) PaddingN() (int, int) {
+	var r string
+	var err error
+	if w.info.IsTtk {
+		r, err = evalAsString(fmt.Sprintf("%v cget -padding", w.id))
+	} else {
+		r1, _ := evalAsString(fmt.Sprintf("%v cget -padx", w.id))
+		r2, _ := evalAsString(fmt.Sprintf("%v cget -pady", w.id))
+		r = r1 + " " + r2
+	}
+	return parserPaddingResult(r, err)
+}
+
+func (w *TreeView) SetPadding(pad Pad) error {
+	return w.SetPaddingN(pad.X, pad.Y)
+}
+
+func (w *TreeView) Padding() Pad {
+	x, y := w.PaddingN()
+	return Pad{x, y}
+}
+
+func (w *TreeView) SetTreeSelectMode(mode TreeSelectMode) error {
+	return eval(fmt.Sprintf("%v configure -selectmode {%v}", w.id, mode))
+}
+
+func (w *TreeView) TreeSelectMode() TreeSelectMode {
+	r, err := evalAsString(fmt.Sprintf("%v cget -selectmode", w.id))
+	return parserTreeSelectModeResult(r, err)
+}
+
+func (w *TreeView) SetHeaderHidden(hide bool) error {
+	var value string
+	if hide {
+		value = "tree"
+	} else {
+		value = "tree headings"
+	}
+	return eval(fmt.Sprintf("%v configure -show {%v}", w.id, value))
+}
+
+func (w *TreeView) IsHeaderHidden() bool {
+	r, _ := evalAsString(fmt.Sprintf("%v cget -show", w.id))
+	return r == "tree"
+}
+
+func (w *TreeView) SetColumnCount(columns int) error {
+	if columns < 1 {
+		return ErrInvalid
+	}
+	columns--
+	if columns < 1 {
+		return nil
+	}
+	var ids []string
+	for i := 0; i < columns; i++ {
+		ids = append(ids, fmt.Sprintf("column%v", i))
+	}
+	return eval(fmt.Sprintf("%v configure -columns {%v}", w.id, strings.Join(ids, " ")))
+}
+
+func (w *TreeView) ColumnCount() int {
+	list, err := evalAsStringList(fmt.Sprintf("%v cget -columns", w.id))
+	if err != nil {
+		return 1
+	}
+	return len(list) + 1
+}
+
+func (w *TreeView) SetHeaderLabels(labels []string) error {
+	for n, label := range labels {
+		setObjText("atk_heading_label", label)
+		err := eval(fmt.Sprintf("%v heading #%v -text $atk_heading_label", w.id, n))
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (w *TreeView) SetHeaderLabel(column int, label string) error {
+	setObjText("atk_heading_label", label)
+	return eval(fmt.Sprintf("%v heading #%v -text $atk_heading_label", w.id, column))
+}
+
+func (w *TreeView) HeaderLabel(column int) string {
+	r, _ := evalAsString(fmt.Sprintf("%v heading #%v -text", w.id, column))
+	return r
+}
+
+func (w *TreeView) SetHeaderImage(column int, img *Image) error {
+	var iid string
+	if img != nil {
+		iid = img.Id()
+	}
+	return eval(fmt.Sprintf("%v heading #%v -image {%v}", w.id, column, iid))
+}
+
+func (w *TreeView) HeaderImage(column int) *Image {
+	r, err := evalAsString(fmt.Sprintf("%v heading #%v -image", w.id, column))
+	return parserImageResult(r, err)
+}
+
+func (w *TreeView) SetHeaderAnchor(column int, anchor Anchor) error {
+	return eval(fmt.Sprintf("%v heading #%v -anchor %v", w.id, column, anchor))
+}
+
+func (w *TreeView) HeaderAnchor(column int) Anchor {
+	r, err := evalAsString(fmt.Sprintf("%v heading #%v -anchor", w.id, column))
+	return parserAnchorResult(r, err)
+}
+
+func (w *TreeView) SetColumnWidth(column int, width int) error {
+	return eval(fmt.Sprintf("%v column #%v -width %v", w.id, column, width))
+}
+
+func (w *TreeView) ColumnWidth(column int) int {
+	r, _ := evalAsInt(fmt.Sprintf("%v column #%v -width", w.id, column))
+	return r
+}
+
+func (w *TreeView) SetColumnMinimumWidth(column int, width int) error {
+	return eval(fmt.Sprintf("%v column #%v -minwidth %v", w.id, column, width))
+}
+
+func (w *TreeView) ColumnMinimumWidth(column int) int {
+	r, _ := evalAsInt(fmt.Sprintf("%v column #%v -minwidth", w.id, column))
+	return r
+}
+
+func (w *TreeView) SetColumnAnchor(column int, anchor Anchor) error {
+	return eval(fmt.Sprintf("%v column #%v -anchor %v", w.id, column, anchor))
+}
+
+func (w *TreeView) ColumnAnchor(column int) Anchor {
+	r, err := evalAsString(fmt.Sprintf("%v column #%v -anchor", w.id, column))
+	return parserAnchorResult(r, err)
+}
+
+// default all column stretch 1
+func (w *TreeView) SetColumnStretch(column int, stretch bool) error {
+	return eval(fmt.Sprintf("%v column #%v -stretch %v", w.id, column, stretch))
+}
+
+// default all column stretch 1
+func (w *TreeView) ColumnStretch(column int) bool {
+	r, _ := evalAsBool(fmt.Sprintf("%v column #%v -stretch", w.id, column))
+	return r
+}
+
+func (w *TreeView) IsValidItem(item *TreeItem) bool {
+	return item != nil && item.tree != nil && item.tree.id == w.id
+}
+
+func (w *TreeView) RootItem() *TreeItem {
+	return &TreeItem{w, ""}
+}
+
+func (w *TreeView) ToplevelItems() []*TreeItem {
+	return w.RootItem().Children()
+}
+
+func (w *TreeView) InsertItem(parent *TreeItem, index int, text string, values []string) *TreeItem {
+	var pid string
+	if parent != nil {
+		if !w.IsValidItem(parent) {
+			return nil
+		}
+		pid = parent.id
+	}
+	setObjText("atk_tree_item", text)
+	setObjTextList("atk_tree_values", values)
+	cid := makeTreeItemId(w.id, pid)
+	err := eval(fmt.Sprintf("%v insert {%v} %v -id {%v} -text $atk_tree_item -values $atk_tree_values", w.id, pid, index, cid))
+	if err != nil {
+		return nil
+	}
+	return &TreeItem{w, cid}
+}
+
+func (w *TreeView) DeleteItem(item *TreeItem) error {
+	if !w.IsValidItem(item) || item.IsRoot() {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("%v delete {%v}", w.id, item.id))
+}
+
+func (w *TreeView) DeleteAllItems() error {
+	var ids []string
+	for _, item := range w.RootItem().Children() {
+		ids = append(ids, item.Id())
+	}
+	if len(ids) == 0 {
+		return ErrInvalid
+	}
+	setObjTextList("atk_tmp_items", ids)
+	return eval(fmt.Sprintf("%v delete $atk_tmp_items", w.id))
+}
+
+func (w *TreeView) MoveItem(item *TreeItem, parent *TreeItem, index int) error {
+	if !w.IsValidItem(item) || item.IsRoot() {
+		return ErrInvalid
+	}
+	var pid string
+	if parent != nil {
+		if !w.IsValidItem(parent) {
+			return ErrInvalid
+		}
+		pid = parent.id
+	}
+	return eval(fmt.Sprintf("%v move {%v} {%v} %v", w.id, item.id, pid, index))
+}
+
+func (w *TreeView) ScrollTo(item *TreeItem) error {
+	if !w.IsValidItem(item) || item.IsRoot() {
+		return ErrInvalid
+	}
+	children := w.RootItem().Children()
+	if len(children) == 0 {
+		return ErrInvalid
+	}
+	//fix see bug: first scroll to root
+	eval(fmt.Sprintf("%v see %v", w.id, children[0].id))
+	return eval(fmt.Sprintf("%v see %v", w.id, item.id))
+}
+
+func (w *TreeView) CurrentIndex() *TreeItem {
+	lst := w.SelectionList()
+	if len(lst) == 0 {
+		return nil
+	}
+	return lst[0]
+}
+
+func (w *TreeView) SetCurrentIndex(item *TreeItem) error {
+	return w.SetSelections(item)
+}
+
+func (w *TreeView) SelectionList() (lst []*TreeItem) {
+	ids, err := evalAsStringList(fmt.Sprintf("%v selection", w.id))
+	if err != nil {
+		return
+	}
+	for _, id := range ids {
+		lst = append(lst, &TreeItem{w, id})
+	}
+	return lst
+}
+
+func (w *TreeView) SetSelections(items ...*TreeItem) error {
+	return w.SetSelectionList(items)
+}
+
+func (w *TreeView) RemoveSelections(items ...*TreeItem) error {
+	return w.RemoveSelectionList(items)
+}
+
+func (w *TreeView) AddSelections(items ...*TreeItem) error {
+	return w.AddSelectionList(items)
+}
+
+func (w *TreeView) ToggleSelections(items ...*TreeItem) error {
+	return w.ToggleSelectionList(items)
+}
+
+func (w *TreeView) SetSelectionList(items []*TreeItem) error {
+	var ids []string
+	for _, item := range items {
+		if w.IsValidItem(item) && !item.IsRoot() {
+			ids = append(ids, item.id)
+		}
+	}
+	if len(ids) == 0 {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("%v selection set {%v}", w.id, strings.Join(ids, " ")))
+}
+
+func (w *TreeView) RemoveSelectionList(items []*TreeItem) error {
+	var ids []string
+	for _, item := range items {
+		if w.IsValidItem(item) && !item.IsRoot() {
+			ids = append(ids, item.id)
+		}
+	}
+	if len(ids) == 0 {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("%v selection remove {%v}", w.id, strings.Join(ids, " ")))
+}
+
+func (w *TreeView) AddSelectionList(items []*TreeItem) error {
+	var ids []string
+	for _, item := range items {
+		if w.IsValidItem(item) && !item.IsRoot() {
+			ids = append(ids, item.id)
+		}
+	}
+	if len(ids) == 0 {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("%v selection add {%v}", w.id, strings.Join(ids, " ")))
+}
+
+func (w *TreeView) ToggleSelectionList(items []*TreeItem) error {
+	var ids []string
+	for _, item := range items {
+		if w.IsValidItem(item) && !item.IsRoot() {
+			ids = append(ids, item.id)
+		}
+	}
+	if len(ids) == 0 {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("%v selection toggle {%v}", w.id, strings.Join(ids, " ")))
+}
+
+func (w *TreeView) ExpandAll() error {
+	return w.RootItem().ExpandAll()
+}
+
+func (w *TreeView) CollepseAll() error {
+	return w.RootItem().CollapseAll()
+}
+
+func (w *TreeView) Expand(item *TreeItem) error {
+	return w.SetExpanded(item, true)
+}
+
+func (w *TreeView) Collapse(item *TreeItem) error {
+	return w.SetExpanded(item, false)
+}
+
+func (w *TreeView) SetExpanded(item *TreeItem, expand bool) error {
+	if !w.IsValidItem(item) || item.IsRoot() {
+		return ErrInvalid
+	}
+	return item.SetExpanded(expand)
+}
+
+func (w *TreeView) IsExpanded(item *TreeItem) bool {
+	if !w.IsValidItem(item) || item.IsRoot() {
+		return false
+	}
+	return item.IsExpanded()
+}
+
+func (w *TreeView) FocusItem() *TreeItem {
+	r, _ := evalAsString(fmt.Sprintf("%v focus", w.id))
+	if r == "" {
+		return nil
+	}
+	return &TreeItem{w, r}
+}
+
+func (w *TreeView) SetFocusItem(item *TreeItem) error {
+	if !w.IsValidItem(item) || item.IsRoot() {
+		return ErrInvalid
+	}
+	return eval(fmt.Sprintf("%v focus %v", w.id, item.id))
+}
+
+func (w *TreeView) OnSelectionChanged(fn func()) error {
+	if fn == nil {
+		return ErrInvalid
+	}
+	return w.BindEvent("<<TreeviewSelect>>", func(e *Event) {
+		fn()
+	})
+}
+
+func (w *TreeView) OnItemExpanded(fn func()) error {
+	if fn == nil {
+		return ErrInvalid
+	}
+	return w.BindEvent("<<TreeviewOpen>>", func(e *Event) {
+		fn()
+	})
+}
+
+func (w *TreeView) OnItemCollapsed(fn func()) error {
+	if fn == nil {
+		return ErrInvalid
+	}
+	return w.BindEvent("<<TreeviewSelect>>", func(e *Event) {
+		fn()
+	})
+}
+
+func (w *TreeView) ItemAt(x int, y int) *TreeItem {
+	id, err := evalAsString(fmt.Sprintf("%v identify item %v %v", w.id, x, y))
+	if err != nil {
+		return nil
+	}
+	if id == "" {
+		return nil
+	}
+	return &TreeItem{w, id}
+}
+
+func (w *TreeView) OnDoubleClickedItem(fn func(item *TreeItem)) {
+	if fn == nil {
+		return
+	}
+	w.BindEvent("<Double-ButtonPress-1>", func(e *Event) {
+		item := w.ItemAt(e.PosX, e.PosY)
+		fn(item)
+	})
+}
+
+func (w *TreeView) SetXViewArgs(args []string) error {
+	return eval(fmt.Sprintf("%v xview %v", w.id, strings.Join(args, " ")))
+}
+
+func (w *TreeView) SetYViewArgs(args []string) error {
+	return eval(fmt.Sprintf("%v yview %v", w.id, strings.Join(args, " ")))
+}
+
+func (w *TreeView) OnXScrollEx(fn func([]string) error) error {
+	if fn == nil {
+		return ErrInvalid
+	}
+	if w.xscrollcommand == nil {
+		w.xscrollcommand = &CommandEx{}
+		bindCommandEx(w.id, "xscrollcommand", w.xscrollcommand.Invoke)
+	}
+	w.xscrollcommand.Bind(fn)
+	return nil
+}
+
+func (w *TreeView) OnYScrollEx(fn func([]string) error) error {
+	if fn == nil {
+		return ErrInvalid
+	}
+	if w.yscrollcommand == nil {
+		w.yscrollcommand = &CommandEx{}
+		bindCommandEx(w.id, "yscrollcommand", w.yscrollcommand.Invoke)
+	}
+	w.yscrollcommand.Bind(fn)
+	return nil
+}
+
+func (w *TreeView) BindXScrollBar(bar *ScrollBar) error {
+	if !IsValidWidget(bar) {
+		return ErrInvalid
+	}
+	w.OnXScrollEx(bar.SetScrollArgs)
+	bar.OnCommandEx(w.SetXViewArgs)
+	return nil
+}
+
+func (w *TreeView) BindYScrollBar(bar *ScrollBar) error {
+	if !IsValidWidget(bar) {
+		return ErrInvalid
+	}
+	w.OnYScrollEx(bar.SetScrollArgs)
+	bar.OnCommandEx(w.SetYViewArgs)
+	return nil
+}
+
+type TreeViewEx struct {
+	*ScrollLayout
+	*TreeView
+}
+
+func NewTreeViewEx(parent Widget, attributs ...*WidgetAttr) *TreeViewEx {
+	w := &TreeViewEx{}
+	w.ScrollLayout = NewScrollLayout(parent)
+	w.TreeView = NewTreeView(parent, attributs...)
+	w.SetWidget(w.TreeView)
+	w.TreeView.BindXScrollBar(w.XScrollBar)
+	w.TreeView.BindYScrollBar(w.YScrollBar)
+	RegisterWidget(w)
+	return w
+}
+
+func TreeViewAttrTakeFocus(takefocus bool) *WidgetAttr {
+	return &WidgetAttr{"takefocus", boolToInt(takefocus)}
+}
+
+func TreeViewAttrHeight(row int) *WidgetAttr {
+	return &WidgetAttr{"height", row}
+}
+
+func TreeViewAttrPadding(padding Pad) *WidgetAttr {
+	return &WidgetAttr{"padding", padding}
+}
+
+func TreeViewAttrTreeSelectMode(mode TreeSelectMode) *WidgetAttr {
+	return &WidgetAttr{"selectmode", mode}
+}

+ 47 - 0
vendor/github.com/visualfc/atk/tk/utils.go

@@ -0,0 +1,47 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+func parserTwoInt(s string) (n1 int, n2 int) {
+	var p = &n1
+	for _, r := range s {
+		if r == ' ' {
+			p = &n2
+		} else {
+			*p = *p*10 + int(r-'0')
+		}
+	}
+	return
+}
+
+func boolToInt(b bool) int {
+	if b {
+		return 1
+	}
+	return 0
+}
+
+func isValidKey(key string, keys []string) bool {
+	for _, v := range keys {
+		if v == key {
+			return true
+		}
+	}
+	return false
+}
+
+func SubString(text string, start int, end int) string {
+	var n int = -1
+	var r string
+	for _, v := range text {
+		n++
+		if n < start {
+			continue
+		}
+		if n >= end {
+			break
+		}
+		r += string(v)
+	}
+	return r
+}

+ 169 - 0
vendor/github.com/visualfc/atk/tk/widget.go

@@ -0,0 +1,169 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+	"reflect"
+	"strings"
+)
+
+type Widget interface {
+	Id() string
+	Info() *WidgetInfo
+	Type() WidgetType
+	TypeName() string
+	Parent() Widget
+	Children() []Widget
+	IsValid() bool
+	Destroy() error
+	DestroyChildren() error
+	// attribute
+	NativeAttribute(key string) (value string)
+	SetNativeAttribute(key string, value string) error
+	SetAttributes(attributes ...*WidgetAttr) error
+	// event
+	BindEvent(event string, fn func(*Event)) error
+	BindKeyEvent(fn func(e *KeyEvent)) error
+	BindKeyEventEx(fnPress func(e *KeyEvent), fnRelease func(e *KeyEvent)) error
+	BindInfo() []string
+	ClearBind(event string) error
+	// grab
+	SetGrab() error
+	ReleaseGrab() error
+	IsGrab() bool
+	// focus
+	SetFocus() error
+	IsFocus() bool
+	Lower(below Widget) error
+	Raise(above Widget) error
+}
+
+var (
+	globalWidgetMap = make(map[string]Widget)
+)
+
+func IsNilInterface(w Widget) bool {
+	if w == nil {
+		return true
+	}
+	return reflect.ValueOf(w).IsNil()
+}
+
+func RegisterWidget(w Widget) {
+	if IsNilInterface(w) {
+		return
+	}
+	globalWidgetMap[w.Id()] = w
+}
+
+func FindWidget(id string) Widget {
+	return globalWidgetMap[id]
+}
+
+func LookupWidget(id string) (w Widget, ok bool) {
+	w, ok = globalWidgetMap[id]
+	return
+}
+
+func ParentOfWidget(w Widget) Widget {
+	if IsNilInterface(w) {
+		return nil
+	}
+	id := w.Id()
+	if id == "." {
+		return nil
+	}
+	pos := strings.LastIndex(id, ".")
+	if pos == -1 {
+		return nil
+	} else if pos == 0 {
+		return rootWindow
+	}
+	return globalWidgetMap[id[:pos]]
+}
+
+func ChildrenOfWidget(w Widget) (list []Widget) {
+	if IsNilInterface(w) {
+		return nil
+	}
+	id := w.Id()
+	if id == "." {
+		for k, v := range globalWidgetMap {
+			if strings.HasPrefix(k, id) {
+				if k == "." {
+					continue
+				} else if strings.Index(k[1:], ".") >= 0 {
+					continue
+				}
+				list = append(list, v)
+			}
+		}
+	} else {
+		id = id + "."
+		offset := len(id)
+		for k, v := range globalWidgetMap {
+			if strings.HasPrefix(k, id) {
+				if strings.Index(k[offset:], ".") >= 0 {
+					continue
+				}
+				list = append(list, v)
+			}
+		}
+	}
+	return
+}
+
+func removeWidget(id string) {
+	if id == "." {
+		globalWidgetMap = make(map[string]Widget)
+	} else {
+		delete(globalWidgetMap, id)
+		id = id + "."
+		var list []string
+		for k, _ := range globalWidgetMap {
+			if strings.HasPrefix(k, id) {
+				list = append(list, k)
+			}
+		}
+		for _, k := range list {
+			delete(globalWidgetMap, k)
+		}
+	}
+}
+
+func IsValidWidget(w Widget) bool {
+	if IsNilInterface(w) {
+		return false
+	}
+	_, ok := globalWidgetMap[w.Id()]
+	return ok
+}
+
+func DestroyWidget(w Widget) error {
+	if !IsValidWidget(w) {
+		return ErrInvalid
+	}
+	id := w.Id()
+	eval(fmt.Sprintf("destroy %v", id))
+	removeWidget(id)
+	return nil
+}
+
+func dumpWidgetHelp(w Widget, offset string, space string, ar *[]string) {
+	s := fmt.Sprintf("%v%v", space, w)
+	*ar = append(*ar, s)
+	for _, child := range w.Children() {
+		dumpWidgetHelp(child, offset, space+offset, ar)
+	}
+}
+
+func DumpWidget(w Widget) string {
+	return DumpWidgetEx(w, "\t")
+}
+
+func DumpWidgetEx(w Widget, offset string) string {
+	var ar []string
+	dumpWidgetHelp(w, offset, "", &ar)
+	return strings.Join(ar, "\n")
+}

+ 91 - 0
vendor/github.com/visualfc/atk/tk/widget_attr.go

@@ -0,0 +1,91 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+)
+
+// widget attribute
+type WidgetAttr struct {
+	key   string
+	value interface{}
+}
+
+// setup widget init enable/disable theme
+func WidgetAttrInitUseTheme(use bool) *WidgetAttr {
+	return &WidgetAttr{"init_use_theme", use}
+}
+
+// setup widget font
+func WidgetAttrFont(font Font) *WidgetAttr {
+	if font == nil {
+		return nil
+	}
+	return &WidgetAttr{"font", font.Id()}
+}
+
+// setup widget width
+func WidgetAttrWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"width", width}
+}
+
+// setup widget height pixel or line
+func WidgetAttrHeight(height int) *WidgetAttr {
+	return &WidgetAttr{"height", height}
+}
+
+// setup widget text
+func WidgetAttrText(text string) *WidgetAttr {
+	return &WidgetAttr{"text", text}
+}
+
+// setup widget image
+func WidgetAttrImage(image *Image) *WidgetAttr {
+	if image == nil {
+		return nil
+	}
+	return &WidgetAttr{"image", image.Id()}
+}
+
+// setup widget border style (tk relief attribute)
+func WidgetAttrReliefStyle(style ReliefStyle) *WidgetAttr {
+	return &WidgetAttr{"relief", style}
+}
+
+// setup widget border width
+func WidgetAttrBorderWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"borderwidth", width}
+}
+
+// setup widget padding (ttk padding or tk padx/pady)
+func WidgetAttrPadding(pad Pad) *WidgetAttr {
+	return &WidgetAttr{"padding", pad}
+}
+
+// setup widget padding (ttk padding or tk padx/pady)
+func WidgetAttrPaddingN(padx int, pady int) *WidgetAttr {
+	return &WidgetAttr{"padding", Pad{padx, pady}}
+}
+
+func checkPaddingScript(ttk bool, attr *WidgetAttr) string {
+	if pad, ok := attr.value.(Pad); ok {
+		if ttk {
+			return fmt.Sprintf("-padding {%v %v}", pad.X, pad.Y)
+		} else {
+			return fmt.Sprintf("-padx {%v} -pady {%v}", pad.X, pad.Y)
+		}
+	}
+	return ""
+}
+
+func checkInitUseTheme(attributes []*WidgetAttr) bool {
+	for _, attr := range attributes {
+		if attr != nil && attr.key == "init_use_theme" {
+			if use, ok := attr.value.(bool); ok {
+				return use
+			}
+		}
+	}
+	return mainTheme != nil
+}

+ 927 - 0
vendor/github.com/visualfc/atk/tk/widget_meta.go

@@ -0,0 +1,927 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+var (
+	typeMetaMap = make(map[WidgetType]*MetaType)
+)
+
+type MetaClass struct {
+	Command    string
+	Class      string
+	Attributes []string
+}
+
+func (m *MetaClass) HasAttribute(attr string) bool {
+	if attr == "" {
+		return false
+	}
+	for _, v := range m.Attributes {
+		if v == attr {
+			return true
+		}
+	}
+	return false
+}
+
+type MetaType struct {
+	Type string
+	Tk   *MetaClass
+	Ttk  *MetaClass
+}
+
+func IsTtkClass(class string) bool {
+	for _, v := range ttkClassList {
+		if v == class {
+			return true
+		}
+	}
+	return false
+}
+
+func IsTkClass(class string) bool {
+	for _, v := range tkClassList {
+		if v == class {
+			return true
+		}
+	}
+	return false
+}
+
+var (
+	tkClassList = []string{
+		"Button",
+		"Canvas",
+		"Checkbutton",
+		"Entry",
+		"Frame",
+		"Label",
+		"Labelframe",
+		"Listbox",
+		"Menu",
+		"Menubutton",
+		"Panedwindow",
+		"Radiobutton",
+		"Scale",
+		"Scrollbar",
+		"Spinbox",
+		"Text",
+		"Toplevel",
+	}
+	ttkClassList = []string{
+		"TButton",
+		"TCheckbutton",
+		"TCombobox",
+		"TEntry",
+		"TFrame",
+		"TLabel",
+		"TLabelframe",
+		"TMenubutton",
+		"TNotebook",
+		"TPanedwindow",
+		"TProgressbar",
+		"TRadiobutton",
+		"TScale",
+		"Scrollbar",
+		"TSeparator",
+		"TSizegrip",
+		"Treeview",
+	}
+)
+
+func init() {
+	typeMetaMap[WidgetTypeButton] =
+		&MetaType{
+			Type: "Button",
+			Tk: &MetaClass{"tk::button", "Button",
+				[]string{"activebackground",
+					"activeforeground",
+					"anchor",
+					"background",
+					"bitmap",
+					"borderwidth",
+					"command",
+					"compound",
+					"cursor",
+					"default",
+					"disabledforeground",
+					"font",
+					"foreground",
+					"height",
+					"highlightbackground",
+					"highlightcolor",
+					"highlightthickness",
+					"image",
+					"justify",
+					"overrelief",
+					"padx",
+					"pady",
+					"relief",
+					"repeatdelay",
+					"repeatinterval",
+					"state",
+					"takefocus",
+					"text",
+					"textvariable",
+					"underline",
+					"width",
+					"wraplength"}},
+			Ttk: &MetaClass{"ttk::button", "TButton",
+				[]string{"command",
+					"default",
+					"takefocus",
+					"text",
+					"textvariable",
+					"underline",
+					"width",
+					"image",
+					"compound",
+					"padding",
+					"state",
+					"cursor",
+					"style",
+					"class"}},
+		}
+	typeMetaMap[WidgetTypeCanvas] =
+		&MetaType{
+			Type: "Canvas",
+			Tk: &MetaClass{"tk::canvas", "Canvas",
+				[]string{"background",
+					"borderwidth",
+					"closeenough",
+					"confine",
+					"cursor",
+					"height",
+					"highlightbackground",
+					"highlightcolor",
+					"highlightthickness",
+					"insertbackground",
+					"insertborderwidth",
+					"insertofftime",
+					"insertontime",
+					"insertwidth",
+					"offset",
+					"relief",
+					"scrollregion",
+					"selectbackground",
+					"selectborderwidth",
+					"selectforeground",
+					"state",
+					"takefocus",
+					"width",
+					"xscrollcommand",
+					"xscrollincrement",
+					"yscrollcommand",
+					"yscrollincrement"}},
+			Ttk: nil,
+		}
+	typeMetaMap[WidgetTypeCheckButton] =
+		&MetaType{
+			Type: "CheckButton",
+			Tk: &MetaClass{"tk::checkbutton", "Checkbutton",
+				[]string{"activebackground",
+					"activeforeground",
+					"anchor",
+					"background",
+					"bitmap",
+					"borderwidth",
+					"command",
+					"compound",
+					"cursor",
+					"disabledforeground",
+					"font",
+					"foreground",
+					"height",
+					"highlightbackground",
+					"highlightcolor",
+					"highlightthickness",
+					"image",
+					"indicatoron",
+					"justify",
+					"offrelief",
+					"offvalue",
+					"onvalue",
+					"overrelief",
+					"padx",
+					"pady",
+					"relief",
+					"selectcolor",
+					"selectimage",
+					"state",
+					"takefocus",
+					"text",
+					"textvariable",
+					"tristateimage",
+					"tristatevalue",
+					"underline",
+					"variable",
+					"width",
+					"wraplength"}},
+			Ttk: &MetaClass{"ttk::checkbutton", "TCheckbutton",
+				[]string{"variable",
+					"onvalue",
+					"offvalue",
+					"command",
+					"takefocus",
+					"text",
+					"textvariable",
+					"underline",
+					"width",
+					"image",
+					"compound",
+					"padding",
+					"state",
+					"cursor",
+					"style",
+					"class"}},
+		}
+	typeMetaMap[WidgetTypeComboBox] =
+		&MetaType{
+			Type: "ComboBox",
+			Tk:   nil,
+			Ttk: &MetaClass{"ttk::combobox", "TCombobox",
+				[]string{"height",
+					"postcommand",
+					"values",
+					"exportselection",
+					"font",
+					"invalidcommand",
+					"justify",
+					"show",
+					"state",
+					"textvariable",
+					"validate",
+					"validatecommand",
+					"width",
+					"xscrollcommand",
+					"foreground",
+					"background",
+					"takefocus",
+					"cursor",
+					"style",
+					"class"}},
+		}
+	typeMetaMap[WidgetTypeEntry] =
+		&MetaType{
+			Type: "Entry",
+			Tk: &MetaClass{"tk::entry", "Entry",
+				[]string{"background",
+					"borderwidth",
+					"cursor",
+					"disabledbackground",
+					"disabledforeground",
+					"exportselection",
+					"font",
+					"foreground",
+					"highlightbackground",
+					"highlightcolor",
+					"highlightthickness",
+					"insertbackground",
+					"insertborderwidth",
+					"insertofftime",
+					"insertontime",
+					"insertwidth",
+					"invalidcommand",
+					"justify",
+					"readonlybackground",
+					"relief",
+					"selectbackground",
+					"selectborderwidth",
+					"selectforeground",
+					"show",
+					"state",
+					"takefocus",
+					"textvariable",
+					"validate",
+					"validatecommand",
+					"width",
+					"xscrollcommand"}},
+			Ttk: &MetaClass{"ttk::entry", "TEntry",
+				[]string{"exportselection",
+					"font",
+					"invalidcommand",
+					"justify",
+					"show",
+					"state",
+					"textvariable",
+					"validate",
+					"validatecommand",
+					"width",
+					"xscrollcommand",
+					"foreground",
+					"background",
+					"takefocus",
+					"cursor",
+					"style",
+					"class"}},
+		}
+	typeMetaMap[WidgetTypeFrame] =
+		&MetaType{
+			Type: "Frame",
+			Tk: &MetaClass{"tk::frame", "Frame",
+				[]string{"borderwidth",
+					"class",
+					"relief",
+					"background",
+					"colormap",
+					"container",
+					"cursor",
+					"height",
+					"highlightbackground",
+					"highlightcolor",
+					"highlightthickness",
+					"padx",
+					"pady",
+					"takefocus",
+					"visual",
+					"width"}},
+			Ttk: &MetaClass{"ttk::frame", "TFrame",
+				[]string{"borderwidth",
+					"padding",
+					"relief",
+					"width",
+					"height",
+					"takefocus",
+					"cursor",
+					"style",
+					"class"}},
+		}
+	typeMetaMap[WidgetTypeLabel] =
+		&MetaType{
+			Type: "Label",
+			Tk: &MetaClass{"tk::label", "Label",
+				[]string{"activebackground",
+					"activeforeground",
+					"anchor",
+					"background",
+					"bitmap",
+					"borderwidth",
+					"compound",
+					"cursor",
+					"disabledforeground",
+					"font",
+					"foreground",
+					"height",
+					"highlightbackground",
+					"highlightcolor",
+					"highlightthickness",
+					"image",
+					"justify",
+					"padx",
+					"pady",
+					"relief",
+					"state",
+					"takefocus",
+					"text",
+					"textvariable",
+					"underline",
+					"width",
+					"wraplength"}},
+			Ttk: &MetaClass{"ttk::label", "TLabel",
+				[]string{"background",
+					"foreground",
+					"font",
+					"borderwidth",
+					"relief",
+					"anchor",
+					"justify",
+					"wraplength",
+					"takefocus",
+					"text",
+					"textvariable",
+					"underline",
+					"width",
+					"image",
+					"compound",
+					"padding",
+					"state",
+					"cursor",
+					"style",
+					"class"}},
+		}
+	typeMetaMap[WidgetTypeLabelFrame] =
+		&MetaType{
+			Type: "LabelFrame",
+			Tk: &MetaClass{"tk::labelframe", "Labelframe",
+				[]string{"borderwidth",
+					"class",
+					"font",
+					"foreground",
+					"labelanchor",
+					"labelwidget",
+					"relief",
+					"text",
+					"background",
+					"colormap",
+					"container",
+					"cursor",
+					"height",
+					"highlightbackground",
+					"highlightcolor",
+					"highlightthickness",
+					"padx",
+					"pady",
+					"takefocus",
+					"visual",
+					"width"}},
+			Ttk: &MetaClass{"ttk::labelframe", "TLabelframe",
+				[]string{"labelanchor",
+					"text",
+					"underline",
+					"labelwidget",
+					"borderwidth",
+					"padding",
+					"relief",
+					"width",
+					"height",
+					"takefocus",
+					"cursor",
+					"style",
+					"class"}},
+		}
+	typeMetaMap[WidgetTypeListBox] =
+		&MetaType{
+			Type: "ListBox",
+			Tk: &MetaClass{"tk::listbox", "Listbox",
+				[]string{"activestyle",
+					"background",
+					"borderwidth",
+					"cursor",
+					"disabledforeground",
+					"exportselection",
+					"font",
+					"foreground",
+					"height",
+					"highlightbackground",
+					"highlightcolor",
+					"highlightthickness",
+					"justify",
+					"relief",
+					"selectbackground",
+					"selectborderwidth",
+					"selectforeground",
+					"selectmode",
+					"setgrid",
+					"state",
+					"takefocus",
+					"width",
+					"xscrollcommand",
+					"yscrollcommand",
+					"listvariable"}},
+			Ttk: nil,
+		}
+	typeMetaMap[WidgetTypeMenu] =
+		&MetaType{
+			Type: "Menu",
+			Tk: &MetaClass{"menu", "Menu",
+				[]string{"activebackground",
+					"activeborderwidth",
+					"activeforeground",
+					"background",
+					"borderwidth",
+					"cursor",
+					"disabledforeground",
+					"font",
+					"foreground",
+					"postcommand",
+					"relief",
+					"selectcolor",
+					"takefocus",
+					"tearoff",
+					"tearoffcommand",
+					"title",
+					"type"}},
+			Ttk: nil,
+		}
+	typeMetaMap[WidgetTypeMenuButton] =
+		&MetaType{
+			Type: "MenuButton",
+			Tk: &MetaClass{"tk::menubutton", "Menubutton",
+				[]string{"activebackground",
+					"activeforeground",
+					"anchor",
+					"background",
+					"bitmap",
+					"borderwidth",
+					"cursor",
+					"direction",
+					"disabledforeground",
+					"font",
+					"foreground",
+					"height",
+					"highlightbackground",
+					"highlightcolor",
+					"highlightthickness",
+					"image",
+					"indicatoron",
+					"justify",
+					"menu",
+					"padx",
+					"pady",
+					"relief",
+					"compound",
+					"state",
+					"takefocus",
+					"text",
+					"textvariable",
+					"underline",
+					"width",
+					"wraplength"}},
+			Ttk: &MetaClass{"ttk::menubutton", "TMenubutton",
+				[]string{"menu",
+					"direction",
+					"takefocus",
+					"text",
+					"textvariable",
+					"underline",
+					"width",
+					"image",
+					"compound",
+					"padding",
+					"state",
+					"cursor",
+					"style",
+					"class"}},
+		}
+	typeMetaMap[WidgetTypeNotebook] =
+		&MetaType{
+			Type: "Notebook",
+			Tk:   nil,
+			Ttk: &MetaClass{"ttk::notebook", "TNotebook",
+				[]string{"width",
+					"height",
+					"padding",
+					"takefocus",
+					"cursor",
+					"style",
+					"class"}},
+		}
+	typeMetaMap[WidgetTypePaned] =
+		&MetaType{
+			Type: "Paned",
+			Tk: &MetaClass{"tk::panedwindow", "Panedwindow",
+				[]string{"background",
+					"borderwidth",
+					"cursor",
+					"handlepad",
+					"handlesize",
+					"height",
+					"opaqueresize",
+					"orient",
+					"proxybackground",
+					"proxyborderwidth",
+					"proxyrelief",
+					"relief",
+					"sashcursor",
+					"sashpad",
+					"sashrelief",
+					"sashwidth",
+					"showhandle",
+					"width"}},
+			Ttk: &MetaClass{"ttk::panedwindow", "TPanedwindow",
+				[]string{"orient",
+					"width",
+					"height",
+					"takefocus",
+					"cursor",
+					"style",
+					"class"}},
+		}
+	typeMetaMap[WidgetTypeProgressBar] =
+		&MetaType{
+			Type: "ProgressBar",
+			Tk:   nil,
+			Ttk: &MetaClass{"ttk::progressbar", "TProgressbar",
+				[]string{"orient",
+					"length",
+					"mode",
+					"maximum",
+					"variable",
+					"value",
+					"phase",
+					"takefocus",
+					"cursor",
+					"style",
+					"class"}},
+		}
+	typeMetaMap[WidgetTypeRadioButton] =
+		&MetaType{
+			Type: "RadioButton",
+			Tk: &MetaClass{"tk::radiobutton", "Radiobutton",
+				[]string{"activebackground",
+					"activeforeground",
+					"anchor",
+					"background",
+					"bitmap",
+					"borderwidth",
+					"command",
+					"compound",
+					"cursor",
+					"disabledforeground",
+					"font",
+					"foreground",
+					"height",
+					"highlightbackground",
+					"highlightcolor",
+					"highlightthickness",
+					"image",
+					"indicatoron",
+					"justify",
+					"offrelief",
+					"overrelief",
+					"padx",
+					"pady",
+					"relief",
+					"selectcolor",
+					"selectimage",
+					"state",
+					"takefocus",
+					"text",
+					"textvariable",
+					"tristateimage",
+					"tristatevalue",
+					"underline",
+					"value",
+					"variable",
+					"width",
+					"wraplength"}},
+			Ttk: &MetaClass{"ttk::radiobutton", "TRadiobutton",
+				[]string{"variable",
+					"value",
+					"command",
+					"takefocus",
+					"text",
+					"textvariable",
+					"underline",
+					"width",
+					"image",
+					"compound",
+					"padding",
+					"state",
+					"cursor",
+					"style",
+					"class"}},
+		}
+	typeMetaMap[WidgetTypeScale] =
+		&MetaType{
+			Type: "Scale",
+			Tk: &MetaClass{"tk::scale", "Scale",
+				[]string{"activebackground",
+					"background",
+					"bigincrement",
+					"borderwidth",
+					"command",
+					"cursor",
+					"digits",
+					"font",
+					"foreground",
+					"from",
+					"highlightbackground",
+					"highlightcolor",
+					"highlightthickness",
+					"label",
+					"length",
+					"orient",
+					"relief",
+					"repeatdelay",
+					"repeatinterval",
+					"resolution",
+					"showvalue",
+					"sliderlength",
+					"sliderrelief",
+					"state",
+					"takefocus",
+					"tickinterval",
+					"to",
+					"troughcolor",
+					"variable",
+					"width"}},
+			Ttk: &MetaClass{"ttk::scale", "TScale",
+				[]string{"command",
+					"variable",
+					"orient",
+					"from",
+					"to",
+					"value",
+					"length",
+					"takefocus",
+					"cursor",
+					"style",
+					"class"}},
+		}
+	typeMetaMap[WidgetTypeScrollBar] =
+		&MetaType{
+			Type: "ScrollBar",
+			Tk: &MetaClass{"tk::scrollbar", "Scrollbar",
+				[]string{"activebackground",
+					"activerelief",
+					"background",
+					"borderwidth",
+					"command",
+					"cursor",
+					"elementborderwidth",
+					"highlightbackground",
+					"highlightcolor",
+					"highlightthickness",
+					"jump",
+					"orient",
+					"relief",
+					"repeatdelay",
+					"repeatinterval",
+					"takefocus",
+					"troughcolor",
+					"width"}},
+			Ttk: &MetaClass{"ttk::scrollbar", "Scrollbar",
+				[]string{"command",
+					"orient",
+					"takefocus",
+					"cursor",
+					"style",
+					"class"}},
+		}
+	typeMetaMap[WidgetTypeSeparator] =
+		&MetaType{
+			Type: "Separator",
+			Tk:   nil,
+			Ttk: &MetaClass{"ttk::separator", "TSeparator",
+				[]string{"orient",
+					"takefocus",
+					"cursor",
+					"style",
+					"class"}},
+		}
+	typeMetaMap[WidgetTypeSizeGrip] =
+		&MetaType{
+			Type: "SizeGrip",
+			Tk:   nil,
+			Ttk: &MetaClass{"ttk::sizegrip", "TSizegrip",
+				[]string{"takefocus",
+					"cursor",
+					"style",
+					"class"}},
+		}
+	typeMetaMap[WidgetTypeSpinBox] =
+		&MetaType{
+			Type: "SpinBox",
+			Tk: &MetaClass{"tk::spinbox", "Spinbox",
+				[]string{"activebackground",
+					"background",
+					"borderwidth",
+					"buttonbackground",
+					"buttoncursor",
+					"buttondownrelief",
+					"buttonuprelief",
+					"command",
+					"cursor",
+					"disabledbackground",
+					"disabledforeground",
+					"exportselection",
+					"font",
+					"foreground",
+					"format",
+					"from",
+					"highlightbackground",
+					"highlightcolor",
+					"highlightthickness",
+					"increment",
+					"insertbackground",
+					"insertborderwidth",
+					"insertofftime",
+					"insertontime",
+					"insertwidth",
+					"invalidcommand",
+					"justify",
+					"relief",
+					"readonlybackground",
+					"repeatdelay",
+					"repeatinterval",
+					"selectbackground",
+					"selectborderwidth",
+					"selectforeground",
+					"state",
+					"takefocus",
+					"textvariable",
+					"to",
+					"validate",
+					"validatecommand",
+					"values",
+					"width",
+					"wrap",
+					"xscrollcommand"}},
+			Ttk: &MetaClass{"ttk::spinbox", "TSpinbox",
+				[]string{"values",
+					"from",
+					"to",
+					"increment",
+					"format",
+					"command",
+					"wrap",
+					"exportselection",
+					"font",
+					"invalidcommand",
+					"justify",
+					"show",
+					"state",
+					"textvariable",
+					"validate",
+					"validatecommand",
+					"width",
+					"xscrollcommand",
+					"foreground",
+					"background",
+					"takefocus",
+					"cursor",
+					"style",
+					"class"}},
+		}
+	typeMetaMap[WidgetTypeText] =
+		&MetaType{
+			Type: "Text",
+			Tk: &MetaClass{"tk::text", "Text",
+				[]string{"autoseparators",
+					"background",
+					"blockcursor",
+					"borderwidth",
+					"cursor",
+					"endline",
+					"exportselection",
+					"font",
+					"foreground",
+					"height",
+					"highlightbackground",
+					"highlightcolor",
+					"highlightthickness",
+					"inactiveselectbackground",
+					"insertbackground",
+					"insertborderwidth",
+					"insertofftime",
+					"insertontime",
+					"insertunfocussed",
+					"insertwidth",
+					"maxundo",
+					"padx",
+					"pady",
+					"relief",
+					"selectbackground",
+					"selectborderwidth",
+					"selectforeground",
+					"setgrid",
+					"spacing1",
+					"spacing2",
+					"spacing3",
+					"startline",
+					"state",
+					"tabs",
+					"tabstyle",
+					"takefocus",
+					"undo",
+					"width",
+					"wrap",
+					"xscrollcommand",
+					"yscrollcommand"}},
+			Ttk: nil,
+		}
+	typeMetaMap[WidgetTypeWindow] =
+		&MetaType{
+			Type: "Window",
+			Tk: &MetaClass{"toplevel", "Toplevel",
+				[]string{"borderwidth",
+					"class",
+					"menu",
+					"relief",
+					"screen",
+					"use",
+					"background",
+					"colormap",
+					"container",
+					"cursor",
+					"height",
+					"highlightbackground",
+					"highlightcolor",
+					"highlightthickness",
+					"padx",
+					"pady",
+					"takefocus",
+					"visual",
+					"width"}},
+			Ttk: nil,
+		}
+	typeMetaMap[WidgetTypeTreeView] =
+		&MetaType{
+			Type: "TreeView",
+			Tk:   nil,
+			Ttk: &MetaClass{"ttk::treeview", "Treeview",
+				[]string{"columns",
+					"displaycolumns",
+					"show",
+					"selectmode",
+					"height",
+					"padding",
+					"xscrollcommand",
+					"yscrollcommand",
+					"takefocus",
+					"cursor",
+					"style",
+					"class"}},
+		}
+}

+ 178 - 0
vendor/github.com/visualfc/atk/tk/widget_type.go

@@ -0,0 +1,178 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+	"strings"
+)
+
+var (
+	ErrorInvalidWidgetInfo  = fmt.Errorf("invalid widget info")
+	ErrorNotMatchWidgetInfo = fmt.Errorf("widget info not match")
+)
+
+type WidgetType int
+
+const (
+	WidgetTypeNone WidgetType = iota
+	WidgetTypeButton
+	WidgetTypeCanvas
+	WidgetTypeCheckButton
+	WidgetTypeComboBox
+	WidgetTypeEntry
+	WidgetTypeFrame
+	WidgetTypeLabel
+	WidgetTypeLabelFrame
+	WidgetTypeListBox
+	WidgetTypeMenu
+	WidgetTypeMenuButton
+	WidgetTypeNotebook
+	WidgetTypePaned
+	WidgetTypeProgressBar
+	WidgetTypeRadioButton
+	WidgetTypeScale
+	WidgetTypeScrollBar
+	WidgetTypeSeparator
+	WidgetTypeSizeGrip
+	WidgetTypeSpinBox
+	WidgetTypeText
+	WidgetTypeWindow
+	WidgetTypeTreeView
+	WidgetTypeLayoutFrame
+	WidgetTypeLayoutSpacer
+	WidgetTypeLast
+)
+
+func (typ WidgetType) MetaClass(theme bool) (typName string, meta *MetaClass, ttk bool) {
+	mc, ok := typeMetaMap[typ]
+	if !ok {
+		panic(fmt.Errorf("error find metaclass type:%v", typ))
+	}
+	if theme && mainTheme != nil && mainTheme.IsTtk() {
+		if mc.Ttk != nil {
+			return mc.Type, mc.Ttk, true
+		}
+		return mc.Type, mc.Tk, false
+	}
+	if mc.Tk != nil {
+		return mc.Type, mc.Tk, false
+	}
+	return mc.Type, mc.Ttk, true
+}
+
+func (typ WidgetType) ThemeConfigure() string {
+	if mainTheme == nil {
+		return ""
+	}
+	var list []string
+	attrs := mainTheme.InitAttributes(typ)
+	_, meta, _ := typ.MetaClass(true)
+	for _, attr := range attrs {
+		if !meta.HasAttribute(attr.Key) {
+			continue
+		}
+		list = append(list, fmt.Sprintf("-%v %q", attr.Key, attr.Value))
+	}
+	return strings.Join(list, " ")
+}
+
+type WidgetInfo struct {
+	Type      WidgetType
+	TypeName  string
+	IsTtk     bool
+	MetaClass *MetaClass
+}
+
+func buildWidgetAttributeScript(meta *MetaClass, ttk bool, attributes []*WidgetAttr) string {
+	var list []string
+	for _, attr := range attributes {
+		if attr == nil {
+			continue
+		}
+		if attr.key == "padding" {
+			list = append(list, checkPaddingScript(ttk, attr))
+			continue
+		}
+		if !meta.HasAttribute(attr.key) {
+			continue
+		}
+		if strs, ok := attr.value.([]string); ok {
+			pname := "atk_tmp_" + attr.key
+			setObjTextList(pname, strs)
+			list = append(list, fmt.Sprintf("-%v $%v", attr.key, pname))
+			continue
+		}
+		if s, ok := attr.value.(string); ok {
+			pname := "atk_tmp_" + attr.key
+			setObjText(pname, s)
+			list = append(list, fmt.Sprintf("-%v $%v", attr.key, pname))
+			continue
+		}
+		list = append(list, fmt.Sprintf("-%v {%v}", attr.key, attr.value))
+	}
+	return strings.Join(list, " ")
+}
+
+func CreateWidgetInfo(iid string, typ WidgetType, theme bool, attributes []*WidgetAttr) *WidgetInfo {
+	typName, meta, isttk := typ.MetaClass(theme)
+	script := fmt.Sprintf("%v %v", meta.Command, iid)
+	if theme {
+		cfg := typ.ThemeConfigure()
+		if cfg != "" {
+			script += " " + cfg
+		}
+	}
+	if len(attributes) > 0 {
+		extra := buildWidgetAttributeScript(meta, isttk, attributes)
+		if len(extra) > 0 {
+			script += " " + extra
+		}
+	}
+	err := eval(script)
+	if err != nil {
+		return nil
+	}
+	return &WidgetInfo{typ, typName, isttk, meta}
+}
+
+func findClassById(id string) string {
+	if id == "." {
+		return "Toplevel"
+	}
+	s, err := mainInterp.EvalAsString(fmt.Sprintf("winfo class {%v}", id))
+	if err != nil {
+		return ""
+	}
+	return s
+}
+
+func FindWidgetInfo(id string) *WidgetInfo {
+	if id == "" {
+		return nil
+	}
+	class := findClassById(id)
+	if class == "" {
+		return nil
+	}
+	for k, v := range typeMetaMap {
+		if v.Tk != nil && v.Tk.Class == class {
+			return &WidgetInfo{k, v.Type, false, v.Tk}
+		}
+		if v.Ttk != nil && v.Ttk.Class == class {
+			return &WidgetInfo{k, v.Type, true, v.Ttk}
+		}
+	}
+	return nil
+}
+
+func CheckWidgetInfo(id string, typ WidgetType) (*WidgetInfo, error) {
+	info := FindWidgetInfo(id)
+	if info == nil {
+		return nil, ErrorInvalidWidgetInfo
+	}
+	if info.Type != typ {
+		return nil, ErrorNotMatchWidgetInfo
+	}
+	return info, nil
+}

+ 417 - 0
vendor/github.com/visualfc/atk/tk/window.go

@@ -0,0 +1,417 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+)
+
+type WindowInfo struct {
+	X      int
+	Y      int
+	Width  int
+	Height int
+}
+
+var (
+	globalWindowInfoMap = make(map[string]*WindowInfo)
+)
+
+type WindowWidget interface {
+	Widget
+	SetGeometry(v Geometry) error
+	Geometry() Geometry
+	SetGeometryN(x int, y int, width int, height int) error
+	GeometryN() (x int, y int, width int, height int)
+}
+
+var _ WindowWidget = &Window{}
+
+type Window struct {
+	BaseWidget
+}
+
+func (w *Window) SetTitle(title string) error {
+	setObjText("atk_tmp_title", title)
+	return eval(fmt.Sprintf("wm title %v $atk_tmp_title", w.id))
+}
+
+func (w *Window) Title() string {
+	s, _ := evalAsString(fmt.Sprintf("wm title %v", w.id))
+	return s
+}
+
+func (w *Window) SetAlpha(alpha float64) error {
+	return eval(fmt.Sprintf("wm attributes %v -alpha {%v}", w.id, alpha))
+}
+
+func (w *Window) Alpha() float64 {
+	r, _ := evalAsFloat64(fmt.Sprintf("wm attributes %v -alpha", w.id))
+	return r
+}
+
+func (w *Window) SetFullScreen(full bool) error {
+	return eval(fmt.Sprintf("wm attributes %v -fullscreen %v", w.id, boolToInt(full)))
+}
+
+func (w *Window) IsFullScreen() bool {
+	r, _ := evalAsBool(fmt.Sprintf("wm attributes %v -fullscreen", w.id))
+	return r
+}
+
+func (w *Window) SetTopmost(full bool) error {
+	return eval(fmt.Sprintf("wm attributes %v -topmost %v", w.id, boolToInt(full)))
+}
+
+func (w *Window) IsTopmost() bool {
+	r, _ := evalAsBool(fmt.Sprintf("wm attributes %v -topmost", w.id))
+	return r
+}
+
+func (w *Window) SetGeometryN(x int, y int, width int, height int) error {
+	globalWindowInfoMap[w.id] = &WindowInfo{x, y, width, height}
+	return eval(fmt.Sprintf("wm geometry %v %vx%v+%v+%v", w.id, width, height, x, y))
+}
+
+func (w *Window) SetGeometry(v Geometry) error {
+	return w.SetGeometryN(v.X, v.Y, v.Width, v.Height)
+}
+
+func (w *Window) GeometryN() (x int, y int, width int, height int) {
+	if !w.IsVisible() {
+		if info, ok := globalWindowInfoMap[w.id]; ok {
+			return info.X, info.Y, info.Width, info.Height
+		}
+	}
+	s, err := evalAsString(fmt.Sprintf("update\nwm geometry %v", w.id))
+	if err != nil {
+		return
+	}
+	var ar []*int = []*int{&width, &height, &x, &y}
+	var n *int = ar[0]
+	var index int
+	for _, r := range s {
+		if r == 'x' || r == '+' {
+			index++
+			n = ar[index]
+		} else {
+			*n = *n*10 + int(r-'0')
+		}
+	}
+	return
+}
+
+func (w *Window) Geometry() Geometry {
+	x, y, width, height := w.GeometryN()
+	return Geometry{x, y, width, height}
+}
+
+func (w *Window) MoveN(x int, y int) error {
+	return w.SetPosN(x, y)
+}
+
+func (w *Window) Move(pos Pos) error {
+	return w.SetPosN(pos.X, pos.Y)
+}
+
+func (w *Window) SetPosN(x int, y int) error {
+	globalWindowInfoMap[w.id].X = x
+	globalWindowInfoMap[w.id].Y = y
+	return eval(fmt.Sprintf("wm geometry %v +%v+%v", w.id, x, y))
+}
+
+func (w *Window) SetPos(pos Pos) error {
+	return w.SetPosN(pos.X, pos.Y)
+}
+
+func (w *Window) PosN() (x int, y int) {
+	x, y, _, _ = w.GeometryN()
+	return
+}
+
+func (w *Window) Pos() Pos {
+	x, y, _, _ := w.GeometryN()
+	return Pos{x, y}
+}
+
+func (w *Window) ResizeN(width int, height int) error {
+	return w.SetSizeN(width, height)
+}
+
+func (w *Window) Resize(sz Size) error {
+	return w.SetSizeN(sz.Width, sz.Height)
+}
+
+func (w *Window) SetSizeN(width int, height int) error {
+	globalWindowInfoMap[w.id].Width = width
+	globalWindowInfoMap[w.id].Height = height
+	return eval(fmt.Sprintf("wm geometry %v %vx%v", w.id, width, height))
+}
+
+func (w *Window) SetSize(sz Size) error {
+	return w.SetSizeN(sz.Width, sz.Height)
+}
+
+func (w *Window) SizeN() (width int, height int) {
+	_, _, width, height = w.GeometryN()
+	return
+}
+
+func (w *Window) Size() Size {
+	_, _, width, height := w.GeometryN()
+	return Size{width, height}
+}
+
+func (w *Window) SetWidth(width int) error {
+	_, _, _, height := w.GeometryN()
+	return w.SetSizeN(width, height)
+}
+
+func (w *Window) Width() (width int) {
+	_, _, width, _ = w.GeometryN()
+	return
+}
+
+func (w *Window) SetHeight(height int) error {
+	_, _, width, _ := w.GeometryN()
+	return w.SetSizeN(width, height)
+}
+
+func (w *Window) Height() (height int) {
+	_, _, _, height = w.GeometryN()
+	return
+}
+
+func (w *Window) SetNaturalSize() error {
+	return eval(fmt.Sprintf("wm geometry %v {}", w.id))
+}
+
+func (w *Window) SetResizable(enableWidth bool, enableHeight bool) error {
+	return eval(fmt.Sprintf("wm resizable %v %v %v", w.id, boolToInt(enableWidth), boolToInt(enableHeight)))
+}
+
+func (w *Window) IsResizable() (enableWidth bool, enableHeight bool) {
+	s, err := evalAsString(fmt.Sprintf("wm resizable %v", w.id))
+	if err == nil {
+		n1, n2 := parserTwoInt(s)
+		enableWidth = n1 != 0
+		enableHeight = n2 != 0
+	}
+	return
+}
+
+func (w *Window) Iconify() error {
+	return eval(fmt.Sprintf("wm iconify %v", w.id))
+}
+
+func (w *Window) IsIconify() bool {
+	r, _ := evalAsString(fmt.Sprintf("wm state %v", w.id))
+	return r == "iconic"
+}
+
+func (w *Window) ShowModal() error {
+	w.SetGrab()
+	w.SetFocus()
+	return w.SetVisible(true)
+}
+
+func (w *Window) EndModal() error {
+	w.ReleaseGrab()
+	return w.SetVisible(false)
+}
+
+func (w *Window) Wait() error {
+	return eval(fmt.Sprintf("tkwait window %v", w.Id()))
+}
+
+func (w *Window) ShowNormal() error {
+	if w.IsFullScreen() {
+		w.SetFullScreen(false)
+	}
+	return eval(fmt.Sprintf("wm state %v normal", w.id))
+}
+
+func (w *Window) ShowFullScreen() error {
+	return w.SetFullScreen(true)
+}
+
+func (w *Window) ShowMinimized() error {
+	return w.Iconify()
+}
+
+func (w *Window) IsMinimized() bool {
+	return w.IsIconify()
+}
+
+func (w *Window) Hide() error {
+	return eval(fmt.Sprintf("wm state %v withdrawn", w.id))
+}
+
+func (w *Window) IsVisible() bool {
+	s, _ := evalAsString(fmt.Sprintf("wm state %v", w.id))
+	return s != "withdrawn"
+}
+
+func (w *Window) SetVisible(b bool) error {
+	if w.IsVisible() != b {
+		if b {
+			return w.ShowNormal()
+		} else {
+			return w.Hide()
+		}
+	}
+	return nil
+}
+
+func (w *Window) Deiconify() error {
+	return eval(fmt.Sprintf("wm deiconify %v", w.id))
+}
+
+func (w *Window) SetMaximumSizeN(width int, height int) error {
+	return eval(fmt.Sprintf("wm maxsize %v %v %v", w.id, width, height))
+}
+
+func (w *Window) SetMaximumSize(sz Size) error {
+	return w.SetMaximumSizeN(sz.Width, sz.Height)
+}
+
+func (w *Window) MaximumSizeN() (int, int) {
+	s, _ := evalAsString(fmt.Sprintf("wm maxsize %v", w.id))
+	return parserTwoInt(s)
+}
+
+func (w *Window) MaximumSize() Size {
+	width, height := w.MaximumSizeN()
+	return Size{width, height}
+}
+
+func (w *Window) SetMinimumSizeN(width int, height int) error {
+	return eval(fmt.Sprintf("wm minsize %v %v %v", w.id, width, height))
+}
+
+func (w *Window) SetMinimumSize(sz Size) error {
+	return w.SetMinimumSizeN(sz.Width, sz.Height)
+}
+
+func (w *Window) MinimumSizeN() (int, int) {
+	s, _ := evalAsString(fmt.Sprintf("wm minsize %v", w.id))
+	return parserTwoInt(s)
+}
+
+func (w *Window) MinimumSize() Size {
+	width, height := w.MinimumSizeN()
+	return Size{width, height}
+}
+
+func (w *Window) ScreenSizeN() (width int, height int) {
+	width, _ = evalAsInt(fmt.Sprintf("winfo screenwidth %v", w.id))
+	height, _ = evalAsInt(fmt.Sprintf("winfo screenheight %v", w.id))
+	return
+}
+
+func (w *Window) ScreenSize() Size {
+	width, height := w.ScreenSizeN()
+	return Size{width, height}
+}
+
+func (w *Window) Center(parent WindowWidget) error {
+	var sx, sy, sw, sh int
+	width, height := w.SizeN()
+	if parent == nil {
+		sw, sh = w.ScreenSizeN()
+	} else {
+		sx, sy, sw, sh = parent.GeometryN()
+	}
+	xoff := sx + (sw-width)/2
+	yoff := sy + (sh-height)/2
+	return w.MoveN(xoff, yoff)
+}
+
+func (w *Window) OnClose(fn func() (accept bool)) error {
+	actName := makeActionId()
+	_, err := mainInterp.CreateAction(actName, func([]string) {
+		if fn != nil {
+			if fn() {
+				w.Destroy()
+			}
+		} else {
+			w.Destroy()
+		}
+	})
+	if err != nil {
+		return err
+	}
+	return eval(fmt.Sprintf("wm protocol %v WM_DELETE_WINDOW %v", w.id, actName))
+}
+
+func (w *Window) registerWindowInfo() {
+	//fix init layout size
+	w.SetMinimumSize(w.MinimumSize())
+	globalWindowInfoMap[w.id] = &WindowInfo{0, 0, 200, 200}
+}
+
+func RootWindow() *Window {
+	return rootWindow
+}
+
+func WindowOptId(id string) *WidgetAttr {
+	return &WidgetAttr{"id", id}
+}
+
+func WindowOptBorderWidth(width int) *WidgetAttr {
+	return &WidgetAttr{"borderwidth", width}
+}
+
+func WindowOptReliefStyle(style ReliefStyle) *WidgetAttr {
+	return &WidgetAttr{"relief", style}
+}
+
+func WindowOptPadx(padx int) *WidgetAttr {
+	return &WidgetAttr{"padx", padx}
+}
+
+func WindowOptPady(pady int) *WidgetAttr {
+	return &WidgetAttr{"pady", pady}
+}
+
+func NewWindow(attributes ...*WidgetAttr) *Window {
+	iid := makeNamedId(".atk_window")
+	info := CreateWidgetInfo(iid, WidgetTypeWindow, true, attributes)
+	if info == nil {
+		return nil
+	}
+	w := &Window{}
+	w.id = iid
+	w.info = info
+	if tkWindowInitAutoHide {
+		w.Hide()
+	}
+	w.registerWindowInfo()
+	RegisterWidget(w)
+	return w
+}
+
+func (w *Window) Attach(id string) error {
+	info, err := CheckWidgetInfo(id, WidgetTypeWindow)
+	if err != nil {
+		return err
+	}
+	w.id = id
+	w.info = info
+	w.registerWindowInfo()
+	RegisterWidget(w)
+	return nil
+}
+
+func (w *Window) SetMenu(m *Menu) error {
+	var mid string
+	if m != nil {
+		mid = m.Id()
+	}
+	return eval(fmt.Sprintf("%v configure -menu {%v}", w.id, mid))
+}
+
+func (w *Window) Menu() *Menu {
+	r, err := evalAsString(fmt.Sprintf("%v cget -menu", w.id))
+	return parserMenuResult(r, err)
+}

+ 15 - 0
vendor/github.com/visualfc/atk/tk/window_darwin.go

@@ -0,0 +1,15 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import "fmt"
+
+// NOTE: update must
+func (w *Window) ShowMaximized() error {
+	return eval(fmt.Sprintf("update\nwm state %v zoomed", w.id))
+}
+
+func (w *Window) IsMaximized() bool {
+	r, _ := evalAsString(fmt.Sprintf("wm state %v", w.id))
+	return r == "zoomed"
+}

+ 17 - 0
vendor/github.com/visualfc/atk/tk/window_linux.go

@@ -0,0 +1,17 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import "fmt"
+
+func (w *Window) ShowMaximized() error {
+	if !w.IsVisible() {
+		w.ShowNormal()
+	}
+	return eval(fmt.Sprintf("wm attributes %v -zoomed 1", w.id))
+}
+
+func (w *Window) IsMaximized() bool {
+	r, _ := evalAsBool(fmt.Sprintf("wm attributes %v -zoomed", w.id))
+	return r
+}

+ 16 - 0
vendor/github.com/visualfc/atk/tk/window_windows.go

@@ -0,0 +1,16 @@
+// Copyright 2018 visualfc. All rights reserved.
+
+package tk
+
+import (
+	"fmt"
+)
+
+func (w *Window) ShowMaximized() error {
+	return eval(fmt.Sprintf("wm state %v zoomed", w.id))
+}
+
+func (w *Window) IsMaximized() bool {
+	r, _ := evalAsString(fmt.Sprintf("wm state %v", w.id))
+	return r == "zoomed"
+}

+ 3 - 0
vendor/golang.org/x/sync/AUTHORS

@@ -0,0 +1,3 @@
+# This source code refers to The Go Authors for copyright purposes.
+# The master list of authors is in the main Go distribution,
+# visible at http://tip.golang.org/AUTHORS.

+ 3 - 0
vendor/golang.org/x/sync/CONTRIBUTORS

@@ -0,0 +1,3 @@
+# This source code was written by the Go contributors.
+# The master list of contributors is in the main Go distribution,
+# visible at http://tip.golang.org/CONTRIBUTORS.

+ 27 - 0
vendor/golang.org/x/sync/LICENSE

@@ -0,0 +1,27 @@
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 22 - 0
vendor/golang.org/x/sync/PATENTS

@@ -0,0 +1,22 @@
+Additional IP Rights Grant (Patents)
+
+"This implementation" means the copyrightable works distributed by
+Google as part of the Go project.
+
+Google hereby grants to You a perpetual, worldwide, non-exclusive,
+no-charge, royalty-free, irrevocable (except as stated in this section)
+patent license to make, have made, use, offer to sell, sell, import,
+transfer and otherwise run, modify and propagate the contents of this
+implementation of Go, where such license applies only to those patent
+claims, both currently owned or controlled by Google and acquired in
+the future, licensable by Google that are necessarily infringed by this
+implementation of Go.  This grant does not include claims that would be
+infringed only as a consequence of further modification of this
+implementation.  If you or your agent or exclusive licensee institute or
+order or agree to the institution of patent litigation against any
+entity (including a cross-claim or counterclaim in a lawsuit) alleging
+that this implementation of Go or any code incorporated within this
+implementation of Go constitutes direct or contributory patent
+infringement, or inducement of patent infringement, then any patent
+rights granted to you under this License for this implementation of Go
+shall terminate as of the date such litigation is filed.

+ 372 - 0
vendor/golang.org/x/sync/syncmap/map.go

@@ -0,0 +1,372 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package syncmap provides a concurrent map implementation.
+// It is a prototype for a proposed addition to the sync package
+// in the standard library.
+// (https://golang.org/issue/18177)
+package syncmap
+
+import (
+	"sync"
+	"sync/atomic"
+	"unsafe"
+)
+
+// Map is a concurrent map with amortized-constant-time loads, stores, and deletes.
+// It is safe for multiple goroutines to call a Map's methods concurrently.
+//
+// The zero Map is valid and empty.
+//
+// A Map must not be copied after first use.
+type Map struct {
+	mu sync.Mutex
+
+	// read contains the portion of the map's contents that are safe for
+	// concurrent access (with or without mu held).
+	//
+	// The read field itself is always safe to load, but must only be stored with
+	// mu held.
+	//
+	// Entries stored in read may be updated concurrently without mu, but updating
+	// a previously-expunged entry requires that the entry be copied to the dirty
+	// map and unexpunged with mu held.
+	read atomic.Value // readOnly
+
+	// dirty contains the portion of the map's contents that require mu to be
+	// held. To ensure that the dirty map can be promoted to the read map quickly,
+	// it also includes all of the non-expunged entries in the read map.
+	//
+	// Expunged entries are not stored in the dirty map. An expunged entry in the
+	// clean map must be unexpunged and added to the dirty map before a new value
+	// can be stored to it.
+	//
+	// If the dirty map is nil, the next write to the map will initialize it by
+	// making a shallow copy of the clean map, omitting stale entries.
+	dirty map[interface{}]*entry
+
+	// misses counts the number of loads since the read map was last updated that
+	// needed to lock mu to determine whether the key was present.
+	//
+	// Once enough misses have occurred to cover the cost of copying the dirty
+	// map, the dirty map will be promoted to the read map (in the unamended
+	// state) and the next store to the map will make a new dirty copy.
+	misses int
+}
+
+// readOnly is an immutable struct stored atomically in the Map.read field.
+type readOnly struct {
+	m       map[interface{}]*entry
+	amended bool // true if the dirty map contains some key not in m.
+}
+
+// expunged is an arbitrary pointer that marks entries which have been deleted
+// from the dirty map.
+var expunged = unsafe.Pointer(new(interface{}))
+
+// An entry is a slot in the map corresponding to a particular key.
+type entry struct {
+	// p points to the interface{} value stored for the entry.
+	//
+	// If p == nil, the entry has been deleted and m.dirty == nil.
+	//
+	// If p == expunged, the entry has been deleted, m.dirty != nil, and the entry
+	// is missing from m.dirty.
+	//
+	// Otherwise, the entry is valid and recorded in m.read.m[key] and, if m.dirty
+	// != nil, in m.dirty[key].
+	//
+	// An entry can be deleted by atomic replacement with nil: when m.dirty is
+	// next created, it will atomically replace nil with expunged and leave
+	// m.dirty[key] unset.
+	//
+	// An entry's associated value can be updated by atomic replacement, provided
+	// p != expunged. If p == expunged, an entry's associated value can be updated
+	// only after first setting m.dirty[key] = e so that lookups using the dirty
+	// map find the entry.
+	p unsafe.Pointer // *interface{}
+}
+
+func newEntry(i interface{}) *entry {
+	return &entry{p: unsafe.Pointer(&i)}
+}
+
+// Load returns the value stored in the map for a key, or nil if no
+// value is present.
+// The ok result indicates whether value was found in the map.
+func (m *Map) Load(key interface{}) (value interface{}, ok bool) {
+	read, _ := m.read.Load().(readOnly)
+	e, ok := read.m[key]
+	if !ok && read.amended {
+		m.mu.Lock()
+		// Avoid reporting a spurious miss if m.dirty got promoted while we were
+		// blocked on m.mu. (If further loads of the same key will not miss, it's
+		// not worth copying the dirty map for this key.)
+		read, _ = m.read.Load().(readOnly)
+		e, ok = read.m[key]
+		if !ok && read.amended {
+			e, ok = m.dirty[key]
+			// Regardless of whether the entry was present, record a miss: this key
+			// will take the slow path until the dirty map is promoted to the read
+			// map.
+			m.missLocked()
+		}
+		m.mu.Unlock()
+	}
+	if !ok {
+		return nil, false
+	}
+	return e.load()
+}
+
+func (e *entry) load() (value interface{}, ok bool) {
+	p := atomic.LoadPointer(&e.p)
+	if p == nil || p == expunged {
+		return nil, false
+	}
+	return *(*interface{})(p), true
+}
+
+// Store sets the value for a key.
+func (m *Map) Store(key, value interface{}) {
+	read, _ := m.read.Load().(readOnly)
+	if e, ok := read.m[key]; ok && e.tryStore(&value) {
+		return
+	}
+
+	m.mu.Lock()
+	read, _ = m.read.Load().(readOnly)
+	if e, ok := read.m[key]; ok {
+		if e.unexpungeLocked() {
+			// The entry was previously expunged, which implies that there is a
+			// non-nil dirty map and this entry is not in it.
+			m.dirty[key] = e
+		}
+		e.storeLocked(&value)
+	} else if e, ok := m.dirty[key]; ok {
+		e.storeLocked(&value)
+	} else {
+		if !read.amended {
+			// We're adding the first new key to the dirty map.
+			// Make sure it is allocated and mark the read-only map as incomplete.
+			m.dirtyLocked()
+			m.read.Store(readOnly{m: read.m, amended: true})
+		}
+		m.dirty[key] = newEntry(value)
+	}
+	m.mu.Unlock()
+}
+
+// tryStore stores a value if the entry has not been expunged.
+//
+// If the entry is expunged, tryStore returns false and leaves the entry
+// unchanged.
+func (e *entry) tryStore(i *interface{}) bool {
+	p := atomic.LoadPointer(&e.p)
+	if p == expunged {
+		return false
+	}
+	for {
+		if atomic.CompareAndSwapPointer(&e.p, p, unsafe.Pointer(i)) {
+			return true
+		}
+		p = atomic.LoadPointer(&e.p)
+		if p == expunged {
+			return false
+		}
+	}
+}
+
+// unexpungeLocked ensures that the entry is not marked as expunged.
+//
+// If the entry was previously expunged, it must be added to the dirty map
+// before m.mu is unlocked.
+func (e *entry) unexpungeLocked() (wasExpunged bool) {
+	return atomic.CompareAndSwapPointer(&e.p, expunged, nil)
+}
+
+// storeLocked unconditionally stores a value to the entry.
+//
+// The entry must be known not to be expunged.
+func (e *entry) storeLocked(i *interface{}) {
+	atomic.StorePointer(&e.p, unsafe.Pointer(i))
+}
+
+// LoadOrStore returns the existing value for the key if present.
+// Otherwise, it stores and returns the given value.
+// The loaded result is true if the value was loaded, false if stored.
+func (m *Map) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) {
+	// Avoid locking if it's a clean hit.
+	read, _ := m.read.Load().(readOnly)
+	if e, ok := read.m[key]; ok {
+		actual, loaded, ok := e.tryLoadOrStore(value)
+		if ok {
+			return actual, loaded
+		}
+	}
+
+	m.mu.Lock()
+	read, _ = m.read.Load().(readOnly)
+	if e, ok := read.m[key]; ok {
+		if e.unexpungeLocked() {
+			m.dirty[key] = e
+		}
+		actual, loaded, _ = e.tryLoadOrStore(value)
+	} else if e, ok := m.dirty[key]; ok {
+		actual, loaded, _ = e.tryLoadOrStore(value)
+		m.missLocked()
+	} else {
+		if !read.amended {
+			// We're adding the first new key to the dirty map.
+			// Make sure it is allocated and mark the read-only map as incomplete.
+			m.dirtyLocked()
+			m.read.Store(readOnly{m: read.m, amended: true})
+		}
+		m.dirty[key] = newEntry(value)
+		actual, loaded = value, false
+	}
+	m.mu.Unlock()
+
+	return actual, loaded
+}
+
+// tryLoadOrStore atomically loads or stores a value if the entry is not
+// expunged.
+//
+// If the entry is expunged, tryLoadOrStore leaves the entry unchanged and
+// returns with ok==false.
+func (e *entry) tryLoadOrStore(i interface{}) (actual interface{}, loaded, ok bool) {
+	p := atomic.LoadPointer(&e.p)
+	if p == expunged {
+		return nil, false, false
+	}
+	if p != nil {
+		return *(*interface{})(p), true, true
+	}
+
+	// Copy the interface after the first load to make this method more amenable
+	// to escape analysis: if we hit the "load" path or the entry is expunged, we
+	// shouldn't bother heap-allocating.
+	ic := i
+	for {
+		if atomic.CompareAndSwapPointer(&e.p, nil, unsafe.Pointer(&ic)) {
+			return i, false, true
+		}
+		p = atomic.LoadPointer(&e.p)
+		if p == expunged {
+			return nil, false, false
+		}
+		if p != nil {
+			return *(*interface{})(p), true, true
+		}
+	}
+}
+
+// Delete deletes the value for a key.
+func (m *Map) Delete(key interface{}) {
+	read, _ := m.read.Load().(readOnly)
+	e, ok := read.m[key]
+	if !ok && read.amended {
+		m.mu.Lock()
+		read, _ = m.read.Load().(readOnly)
+		e, ok = read.m[key]
+		if !ok && read.amended {
+			delete(m.dirty, key)
+		}
+		m.mu.Unlock()
+	}
+	if ok {
+		e.delete()
+	}
+}
+
+func (e *entry) delete() (hadValue bool) {
+	for {
+		p := atomic.LoadPointer(&e.p)
+		if p == nil || p == expunged {
+			return false
+		}
+		if atomic.CompareAndSwapPointer(&e.p, p, nil) {
+			return true
+		}
+	}
+}
+
+// Range calls f sequentially for each key and value present in the map.
+// If f returns false, range stops the iteration.
+//
+// Range does not necessarily correspond to any consistent snapshot of the Map's
+// contents: no key will be visited more than once, but if the value for any key
+// is stored or deleted concurrently, Range may reflect any mapping for that key
+// from any point during the Range call.
+//
+// Range may be O(N) with the number of elements in the map even if f returns
+// false after a constant number of calls.
+func (m *Map) Range(f func(key, value interface{}) bool) {
+	// We need to be able to iterate over all of the keys that were already
+	// present at the start of the call to Range.
+	// If read.amended is false, then read.m satisfies that property without
+	// requiring us to hold m.mu for a long time.
+	read, _ := m.read.Load().(readOnly)
+	if read.amended {
+		// m.dirty contains keys not in read.m. Fortunately, Range is already O(N)
+		// (assuming the caller does not break out early), so a call to Range
+		// amortizes an entire copy of the map: we can promote the dirty copy
+		// immediately!
+		m.mu.Lock()
+		read, _ = m.read.Load().(readOnly)
+		if read.amended {
+			read = readOnly{m: m.dirty}
+			m.read.Store(read)
+			m.dirty = nil
+			m.misses = 0
+		}
+		m.mu.Unlock()
+	}
+
+	for k, e := range read.m {
+		v, ok := e.load()
+		if !ok {
+			continue
+		}
+		if !f(k, v) {
+			break
+		}
+	}
+}
+
+func (m *Map) missLocked() {
+	m.misses++
+	if m.misses < len(m.dirty) {
+		return
+	}
+	m.read.Store(readOnly{m: m.dirty})
+	m.dirty = nil
+	m.misses = 0
+}
+
+func (m *Map) dirtyLocked() {
+	if m.dirty != nil {
+		return
+	}
+
+	read, _ := m.read.Load().(readOnly)
+	m.dirty = make(map[interface{}]*entry, len(read.m))
+	for k, e := range read.m {
+		if !e.tryExpungeLocked() {
+			m.dirty[k] = e
+		}
+	}
+}
+
+func (e *entry) tryExpungeLocked() (isExpunged bool) {
+	p := atomic.LoadPointer(&e.p)
+	for p == nil {
+		if atomic.CompareAndSwapPointer(&e.p, nil, expunged) {
+			return true
+		}
+		p = atomic.LoadPointer(&e.p)
+	}
+	return p == expunged
+}

+ 7 - 0
vendor/modules.txt

@@ -100,9 +100,16 @@ github.com/valyala/fasthttp/stackless
 # github.com/valyala/tcplisten v1.0.0
 ## explicit; go 1.12
 github.com/valyala/tcplisten
+# github.com/visualfc/atk v1.2.3
+## explicit; go 1.14
+github.com/visualfc/atk/tk
+github.com/visualfc/atk/tk/interp
 # golang.org/x/image v0.0.0-20220302094943-723b81ca9867
 ## explicit; go 1.12
 golang.org/x/image/colornames
+# golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f
+## explicit
+golang.org/x/sync/syncmap
 # golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab
 ## explicit; go 1.17
 golang.org/x/sys/internal/unsafeheader