Browse Source

Merge pull request #22 from grissiom/rtgui-0.6

sync with rtgui-0.6
Bernard Xiong 12 years ago
parent
commit
9400f237b2
100 changed files with 6568 additions and 1064 deletions
  1. 124 124
      components/external/lzo/README.LZO
  2. 1 6
      components/external/lzo/lzo.c
  3. 5 3
      components/external/tjpgd1a/SConscript
  4. 2 0
      components/rtgui/.gitignore
  5. 1826 0
      components/rtgui/Doxyfile
  6. 2 0
      components/rtgui/SConscript
  7. 97 194
      components/rtgui/common/asc12font.c
  8. 97 259
      components/rtgui/common/asc16font.c
  9. 0 7
      components/rtgui/common/dc_hw.c
  10. 3 2
      components/rtgui/common/font_bmp.c
  11. 2 0
      components/rtgui/common/image_jpg.c
  12. 10 0
      components/rtgui/common/region.c
  13. 38 52
      components/rtgui/common/rtgui_app.c
  14. 1 1
      components/rtgui/common/rtgui_mv_model.c
  15. 17 43
      components/rtgui/common/rtgui_system.c
  16. 13 10
      components/rtgui/common/rtgui_theme.c
  17. 69 0
      components/rtgui/doc/ANNOUNCE.0.6.md
  18. 0 0
      components/rtgui/doc/historical/road_map.txt
  19. 81 0
      components/rtgui/doc/mv-model.dox
  20. 8 0
      components/rtgui/include/rtgui/dc.h
  21. 34 3
      components/rtgui/include/rtgui/driver.h
  22. 4 2
      components/rtgui/include/rtgui/event.h
  23. 56 55
      components/rtgui/include/rtgui/region.h
  24. 5 0
      components/rtgui/include/rtgui/rtgui.h
  25. 14 9
      components/rtgui/include/rtgui/rtgui_app.h
  26. 2 2
      components/rtgui/include/rtgui/rtgui_server.h
  27. 6 6
      components/rtgui/include/rtgui/rtgui_system.h
  28. 36 0
      components/rtgui/include/rtgui/widgets/digfont.h
  29. 68 0
      components/rtgui/include/rtgui/widgets/digtube.h
  30. 1 1
      components/rtgui/include/rtgui/widgets/menu.h
  31. 20 2
      components/rtgui/include/rtgui/widgets/textbox.h
  32. 106 107
      components/rtgui/include/rtgui/widgets/widget.h
  33. 1 1
      components/rtgui/include/rtgui/widgets/window.h
  34. 37 0
      components/rtgui/server/driver.c
  35. 15 0
      components/rtgui/server/mouse.c
  36. 2 0
      components/rtgui/server/mouse.h
  37. 42 31
      components/rtgui/server/server.c
  38. 10 10
      components/rtgui/server/topwin.c
  39. 49 0
      components/rtgui/utils/perfect_hash/README
  40. 0 0
      components/rtgui/utils/perfect_hash/__init__.py
  41. 7 0
      components/rtgui/utils/perfect_hash/animals.txt
  42. 22 0
      components/rtgui/utils/perfect_hash/doc/Makefile
  43. BIN
      components/rtgui/utils/perfect_hash/doc/czech92optimal.pdf
  44. 136 0
      components/rtgui/utils/perfect_hash/doc/doc.html
  45. 130 0
      components/rtgui/utils/perfect_hash/doc/doc.in
  46. 141 0
      components/rtgui/utils/perfect_hash/doc/doc.txt
  47. 22 0
      components/rtgui/utils/perfect_hash/doc/mktable.py
  48. 11 0
      components/rtgui/utils/perfect_hash/doc/parameters.txt
  49. 31 0
      components/rtgui/utils/perfect_hash/example-C++/Makefile
  50. 24 0
      components/rtgui/utils/perfect_hash/example-C++/main.cc
  51. 10 0
      components/rtgui/utils/perfect_hash/example-C++/mk_header.py
  52. 19 0
      components/rtgui/utils/perfect_hash/example-C++/states-code.hh
  53. 55 0
      components/rtgui/utils/perfect_hash/example-C++/states-tmpl.cc
  54. 52 0
      components/rtgui/utils/perfect_hash/example-C++/states.dat
  55. 26 0
      components/rtgui/utils/perfect_hash/example-PyModule/Makefile
  56. 12 0
      components/rtgui/utils/perfect_hash/example-PyModule/stations-tmpl.h
  57. 500 0
      components/rtgui/utils/perfect_hash/example-PyModule/stations.dat
  58. 69 0
      components/rtgui/utils/perfect_hash/example-PyModule/stationsmodule.c
  59. 28 0
      components/rtgui/utils/perfect_hash/example-PyModule/test.py
  60. 40 0
      components/rtgui/utils/perfect_hash/example-Python/Graph.py
  61. 15 0
      components/rtgui/utils/perfect_hash/example-Python/Makefile
  62. 40 0
      components/rtgui/utils/perfect_hash/example-Python/PerfHash.py
  63. 38 0
      components/rtgui/utils/perfect_hash/example-Python/generate_hash.py
  64. 31 0
      components/rtgui/utils/perfect_hash/example1-C/Makefile
  65. 33 0
      components/rtgui/utils/perfect_hash/example1-C/main.c
  66. 10 0
      components/rtgui/utils/perfect_hash/example1-C/mk_header.py
  67. 6 0
      components/rtgui/utils/perfect_hash/example1-C/states-code.h
  68. 42 0
      components/rtgui/utils/perfect_hash/example1-C/states-tmpl.c
  69. 52 0
      components/rtgui/utils/perfect_hash/example1-C/states.dat
  70. 22 0
      components/rtgui/utils/perfect_hash/example2-C/Makefile
  71. 13 0
      components/rtgui/utils/perfect_hash/example2-C/keys.tmpl.h
  72. 51 0
      components/rtgui/utils/perfect_hash/example2-C/main.c
  73. 17 0
      components/rtgui/utils/perfect_hash/example2-C/mk_rnd_keys.py
  74. 23 0
      components/rtgui/utils/perfect_hash/graph/Makefile
  75. 4 0
      components/rtgui/utils/perfect_hash/graph/example-pipeline
  76. 216 0
      components/rtgui/utils/perfect_hash/graph/py2dot
  77. 870 0
      components/rtgui/utils/perfect_hash/perfect_hash.py
  78. 32 0
      components/rtgui/utils/perfect_hash/run
  79. 163 0
      components/rtgui/utils/stract_cjk.py
  80. 6 6
      components/rtgui/widgets/box.c
  81. 9 5
      components/rtgui/widgets/button.c
  82. 4 4
      components/rtgui/widgets/combobox.c
  83. 309 0
      components/rtgui/widgets/digfont.c
  84. 174 0
      components/rtgui/widgets/digtube.c
  85. 1 1
      components/rtgui/widgets/filelist_view.c
  86. 7 7
      components/rtgui/widgets/menu.c
  87. 2 1
      components/rtgui/widgets/notebook.c
  88. 4 4
      components/rtgui/widgets/radiobox.c
  89. 4 4
      components/rtgui/widgets/slider.c
  90. 4 4
      components/rtgui/widgets/staticline.c
  91. 26 20
      components/rtgui/widgets/textbox.c
  92. 17 9
      components/rtgui/widgets/widget.c
  93. 30 20
      components/rtgui/widgets/window.c
  94. 1 0
      examples/gui/SConscript
  95. 2 1
      examples/gui/demo_application.c
  96. 8 5
      examples/gui/demo_plot.c
  97. 2 2
      examples/gui/demo_view_benchmark.c
  98. 1 1
      examples/gui/demo_view_box.c
  99. 20 20
      examples/gui/demo_view_button.c
  100. 20 20
      examples/gui/demo_view_checkbox.c

+ 124 - 124
components/external/lzo/README.LZO

@@ -1,124 +1,124 @@
-
- ============================================================================
- miniLZO -- mini subset of the LZO real-time data compression library
- ============================================================================
-
- Author  : Markus Franz Xaver Johannes Oberhumer
-           <markus@oberhumer.com>
-           http://www.oberhumer.com/opensource/lzo/
- Version : 2.06
- Date    : 12 Aug 2011
-
- I've created miniLZO for projects where it is inconvenient to
- include (or require) the full LZO source code just because you
- want to add a little bit of data compression to your application.
-
- miniLZO implements the LZO1X-1 compressor and both the standard and
- safe LZO1X decompressor. Apart from fast compression it also useful
- for situations where you want to use pre-compressed data files (which
- must have been compressed with LZO1X-999).
-
- miniLZO consists of one C source file and three header files:
-    minilzo.c
-    minilzo.h, lzoconf.h, lzodefs.h
-
- To use miniLZO just copy these files into your source directory, add
- minilzo.c to your Makefile and #include minilzo.h from your program.
- Note: you also must distribute this file ('README.LZO') with your project.
-
- minilzo.o compiles to about 6 KiB (using gcc or Visual C on an i386), and
- the sources are about 30 KiB when packed with zip - so there's no more
- excuse that your application doesn't support data compression :-)
-
- For more information, documentation, example programs and other support
- files (like Makefiles and build scripts) please download the full LZO
- package from
-    http://www.oberhumer.com/opensource/lzo/
-
- Have fun,
-  Markus
-
-
- P.S. minilzo.c is generated automatically from the LZO sources and
-      therefore functionality is completely identical
-
-
- Appendix A: building miniLZO
- ----------------------------
- miniLZO is written such a way that it should compile and run
- out-of-the-box on most machines.
-
- If you are running on a very unusual architecture and lzo_init() fails then
- you should first recompile with '-DLZO_DEBUG' to see what causes the failure.
- The most probable case is something like 'sizeof(void *) != sizeof(size_t)'.
- After identifying the problem you can compile by adding some defines
- like '-DSIZEOF_VOID_P=8' to your Makefile.
-
- The best solution is (of course) using Autoconf - if your project uses
- Autoconf anyway just add '-DMINILZO_HAVE_CONFIG_H' to your compiler
- flags when compiling minilzo.c. See the LZO distribution for an example
- how to set up configure.ac.
-
-
- Appendix B: list of public functions available in miniLZO
- ---------------------------------------------------------
- Library initialization
-    lzo_init()
-
- Compression
-    lzo1x_1_compress()
-
- Decompression
-    lzo1x_decompress()
-    lzo1x_decompress_safe()
-
- Checksum functions
-    lzo_adler32()
-
- Version functions
-    lzo_version()
-    lzo_version_string()
-    lzo_version_date()
-
- Portable (but slow) string functions
-    lzo_memcmp()
-    lzo_memcpy()
-    lzo_memmove()
-    lzo_memset()
-
-
- Appendix C: suggested macros for 'configure.ac' when using Autoconf
- -------------------------------------------------------------------
- Checks for typedefs and structures
-    AC_CHECK_TYPE(ptrdiff_t,long)
-    AC_TYPE_SIZE_T
-    AC_CHECK_SIZEOF(short)
-    AC_CHECK_SIZEOF(int)
-    AC_CHECK_SIZEOF(long)
-    AC_CHECK_SIZEOF(long long)
-    AC_CHECK_SIZEOF(__int64)
-    AC_CHECK_SIZEOF(void *)
-    AC_CHECK_SIZEOF(size_t)
-    AC_CHECK_SIZEOF(ptrdiff_t)
-
- Checks for compiler characteristics
-    AC_C_CONST
-
- Checks for library functions
-    AC_CHECK_FUNCS(memcmp memcpy memmove memset)
-
-
- Appendix D: Copyright
- ---------------------
- LZO and miniLZO are Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001,
- 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
- Markus Franz Xaver Oberhumer <markus@oberhumer.com>.
-
- LZO and miniLZO are distributed under the terms of the GNU General
- Public License (GPL).  See the file COPYING.
-
- Special licenses for commercial and other applications which
- are not willing to accept the GNU General Public License
- are available by contacting the author.
-
-
+
+ ============================================================================
+ miniLZO -- mini subset of the LZO real-time data compression library
+ ============================================================================
+
+ Author  : Markus Franz Xaver Johannes Oberhumer
+           <markus@oberhumer.com>
+           http://www.oberhumer.com/opensource/lzo/
+ Version : 2.06
+ Date    : 12 Aug 2011
+
+ I've created miniLZO for projects where it is inconvenient to
+ include (or require) the full LZO source code just because you
+ want to add a little bit of data compression to your application.
+
+ miniLZO implements the LZO1X-1 compressor and both the standard and
+ safe LZO1X decompressor. Apart from fast compression it also useful
+ for situations where you want to use pre-compressed data files (which
+ must have been compressed with LZO1X-999).
+
+ miniLZO consists of one C source file and three header files:
+    minilzo.c
+    minilzo.h, lzoconf.h, lzodefs.h
+
+ To use miniLZO just copy these files into your source directory, add
+ minilzo.c to your Makefile and #include minilzo.h from your program.
+ Note: you also must distribute this file ('README.LZO') with your project.
+
+ minilzo.o compiles to about 6 KiB (using gcc or Visual C on an i386), and
+ the sources are about 30 KiB when packed with zip - so there's no more
+ excuse that your application doesn't support data compression :-)
+
+ For more information, documentation, example programs and other support
+ files (like Makefiles and build scripts) please download the full LZO
+ package from
+    http://www.oberhumer.com/opensource/lzo/
+
+ Have fun,
+  Markus
+
+
+ P.S. minilzo.c is generated automatically from the LZO sources and
+      therefore functionality is completely identical
+
+
+ Appendix A: building miniLZO
+ ----------------------------
+ miniLZO is written such a way that it should compile and run
+ out-of-the-box on most machines.
+
+ If you are running on a very unusual architecture and lzo_init() fails then
+ you should first recompile with '-DLZO_DEBUG' to see what causes the failure.
+ The most probable case is something like 'sizeof(void *) != sizeof(size_t)'.
+ After identifying the problem you can compile by adding some defines
+ like '-DSIZEOF_VOID_P=8' to your Makefile.
+
+ The best solution is (of course) using Autoconf - if your project uses
+ Autoconf anyway just add '-DMINILZO_HAVE_CONFIG_H' to your compiler
+ flags when compiling minilzo.c. See the LZO distribution for an example
+ how to set up configure.ac.
+
+
+ Appendix B: list of public functions available in miniLZO
+ ---------------------------------------------------------
+ Library initialization
+    lzo_init()
+
+ Compression
+    lzo1x_1_compress()
+
+ Decompression
+    lzo1x_decompress()
+    lzo1x_decompress_safe()
+
+ Checksum functions
+    lzo_adler32()
+
+ Version functions
+    lzo_version()
+    lzo_version_string()
+    lzo_version_date()
+
+ Portable (but slow) string functions
+    lzo_memcmp()
+    lzo_memcpy()
+    lzo_memmove()
+    lzo_memset()
+
+
+ Appendix C: suggested macros for 'configure.ac' when using Autoconf
+ -------------------------------------------------------------------
+ Checks for typedefs and structures
+    AC_CHECK_TYPE(ptrdiff_t,long)
+    AC_TYPE_SIZE_T
+    AC_CHECK_SIZEOF(short)
+    AC_CHECK_SIZEOF(int)
+    AC_CHECK_SIZEOF(long)
+    AC_CHECK_SIZEOF(long long)
+    AC_CHECK_SIZEOF(__int64)
+    AC_CHECK_SIZEOF(void *)
+    AC_CHECK_SIZEOF(size_t)
+    AC_CHECK_SIZEOF(ptrdiff_t)
+
+ Checks for compiler characteristics
+    AC_C_CONST
+
+ Checks for library functions
+    AC_CHECK_FUNCS(memcmp memcpy memmove memset)
+
+
+ Appendix D: Copyright
+ ---------------------
+ LZO and miniLZO are Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001,
+ 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+ Markus Franz Xaver Oberhumer <markus@oberhumer.com>.
+
+ LZO and miniLZO are distributed under the terms of the GNU General
+ Public License (GPL).  See the file COPYING.
+
+ Special licenses for commercial and other applications which
+ are not willing to accept the GNU General Public License
+ are available by contacting the author.
+
+

+ 1 - 6
components/external/lzo/lzo.c

@@ -19,13 +19,8 @@
 
 #ifdef _WIN32
 #pragma warning(disable: 4996)
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <io.h>
-#else
-#include <dfs_posix.h>
 #endif
+#include <dfs_posix.h>
 
 /* the worst of allocation */
 #define LZO1X_WORST(x) ( (x) + ((x)/16) + 64 + 3 ) 

+ 5 - 3
components/external/tjpgd1a/SConscript

@@ -1,11 +1,13 @@
+Import('RTT_ROOT')
+Import('rtconfig')
 from building import *
 
-cwd = GetCurrentDir()
-CPPPATH = [cwd]
-src = Split('''
+src	= Split('''
 tjpgd.c
 ''')
 
+CPPPATH = [RTT_ROOT + '/components/external/tjpgd1a']
+
 group = DefineGroup('tjpgd', src, depend = ['RTGUI_IMAGE_TJPGD'], CPPPATH = CPPPATH)
 
 Return('group')

+ 2 - 0
components/rtgui/.gitignore

@@ -0,0 +1,2 @@
+common/font_cmp_hz*.c
+doc/doxygened/

+ 1826 - 0
components/rtgui/Doxyfile

@@ -0,0 +1,1826 @@
+# Doxyfile 1.8.1.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file 
+# that follow. The default is UTF-8 which is also the encoding used for all 
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the 
+# iconv built into libc) for the transcoding. See 
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or sequence of words) that should 
+# identify the project. Note that if you do not use Doxywizard you need 
+# to put quotes around the project name if it contains spaces.
+
+PROJECT_NAME           = "RT-GUI"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = 
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description 
+# for a project that appears at the top of each page and should give viewer 
+# a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          = 
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is 
+# included in the documentation. The maximum height of the logo should not 
+# exceed 55 pixels and the maximum width should not exceed 200 pixels. 
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO           = 
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = doc/doxygened
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
+# 4096 sub-directories (in 2 levels) under the output directory of each output 
+# format and will distribute the generated files over these directories. 
+# Enabling this option can be useful when feeding doxygen a huge amount of 
+# source files, where putting all generated files in the same directory would 
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, 
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English 
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, 
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, 
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = Chinese
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator 
+# that is used to form the text in various listings. Each string 
+# in this list, if found as the leading text of the brief description, will be 
+# stripped from the text and the result after processing the whole list, is 
+# used as the annotated text. Otherwise, the brief description is used as-is. 
+# If left blank, the following values are used ("$name" is automatically 
+# replaced with the name of the entity): "The $name class" "The $name widget" 
+# "The $name file" "is" "provides" "specifies" "contains" 
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 
+# inherited members of a class in the documentation of that class as if those 
+# members were ordinary class members. Constructors, destructors and assignment 
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user-defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. The tag can be used to show relative paths in the file list. 
+# If left blank the directory from which doxygen is run is used as the 
+# path to strip.
+
+STRIP_FROM_PATH        = 
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
+# the path mentioned in the documentation of a class, which tells 
+# the reader which header file to include in order to use a class. 
+# If left blank only the name of the header file containing the class 
+# definition is used. Otherwise one should specify the include paths that 
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = 
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful if your file system 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like regular Qt-style comments 
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will 
+# interpret the first line (until the first dot) of a Qt-style 
+# comment as the brief description. If set to NO, the comments 
+# will behave just like regular Qt-style comments (thus requiring 
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
+# a new page for each member. If set to NO, the documentation of a member will 
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = 
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only). 
+# A mapping has the form "name=value". For example adding 
+# "class=itcl::class" will allow you to use the command class in the 
+# itcl::class meaning.
+
+TCL_SUBST              = 
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
+# sources only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
+# sources only. Doxygen will then generate output that is more tailored for 
+# Java. For instance, namespaces will be presented as packages, qualified 
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran 
+# sources only. Doxygen will then generate output that is more tailored for 
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL 
+# sources. Doxygen will then generate output that is tailored for 
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it 
+# parses. With this tag you can assign which parser to use for a given extension. 
+# Doxygen has a built-in mapping, but you can override or extend it using this 
+# tag. The format is ext=language, where ext is a file extension, and language 
+# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, 
+# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make 
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C 
+# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions 
+# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      = 
+
+# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all 
+# comments according to the Markdown format, which allows for more readable 
+# documentation. See http://daringfireball.net/projects/markdown/ for details. 
+# The output of markdown processing is further processed by doxygen, so you 
+# can mix doxygen, HTML, and XML commands with Markdown formatting. 
+# Disable only in case of backward compatibilities issues.
+
+MARKDOWN_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want 
+# to include (a tag file for) the STL sources as input, then you should 
+# set this tag to YES in order to let doxygen match functions declarations and 
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 
+# func(std::string) {}). This also makes the inheritance and collaboration 
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to 
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. 
+# Doxygen will parse them like normal C++ but will assume all classes use public 
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter 
+# and setter methods for a property. Setting this option to YES (the default) 
+# will make doxygen replace the get and set methods by a property in the 
+# documentation. This will only work if the methods are indeed getting or 
+# setting a simple type. If this is not the case, or you want to show the 
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and 
+# unions are shown inside the group in which they are included (e.g. using 
+# @ingroup) instead of on a separate page (for HTML and Man pages) or 
+# section (for LaTeX and RTF).
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and 
+# unions with only public data fields will be shown inline in the documentation 
+# of the scope in which they are defined (i.e. file, namespace, or group 
+# documentation), provided this scope is documented. If set to NO (the default), 
+# structs, classes, and unions are shown on a separate page (for HTML and Man 
+# pages) or section (for LaTeX and RTF).
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum 
+# is documented as struct, union, or enum with the name of the typedef. So 
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct 
+# with name TypeT. When disabled the typedef will appear as a member of a file, 
+# namespace, or class. And the struct will be named TypeS. This can typically 
+# be useful for C code in case the coding convention dictates that all compound 
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to 
+# determine which symbols to keep in memory and which to flush to disk. 
+# When the cache is full, less often used symbols will be written to disk. 
+# For small to medium size projects (<1000 input files) the default value is 
+# probably good enough. For larger projects a too small cache size can cause 
+# doxygen to be busy swapping symbols to and from disk most of the time 
+# causing a significant performance penalty. 
+# If the system has enough physical memory increasing the cache will improve the 
+# performance by keeping more symbols in memory. Note that the value works on 
+# a logarithmic scale so increasing the size by one will roughly double the 
+# memory usage. The cache size is given by this formula: 
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, 
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+SYMBOL_CACHE_SIZE      = 0
+
+# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be 
+# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given 
+# their name and scope. Since this can be an expensive process and often the 
+# same symbol appear multiple times in the code, doxygen keeps a cache of 
+# pre-resolved symbols. If the cache is too small doxygen will become slower. 
+# If the cache is too large, memory is wasted. The cache size is given by this 
+# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, 
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local 
+# methods, which are defined in the implementation section but not in 
+# the interface are included in the documentation. 
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be 
+# extracted and appear in the documentation as a namespace called 
+# 'anonymous_namespace{file}', where file will be replaced with the base 
+# name of the file that contains the anonymous namespace. By default 
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower-case letters. If set to YES upper-case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen 
+# will list include files with double quotes in the documentation 
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
+# brief documentation of file, namespace and class members alphabetically 
+# by member name. If set to NO (the default) the members will appear in 
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen 
+# will sort the (brief and detailed) documentation of class members so that 
+# constructors and destructors are listed first. If set to NO (the default) 
+# the constructors will appear in the respective orders defined by 
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. 
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO 
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the 
+# hierarchy of group names into alphabetical order. If set to NO (the default) 
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
+# sorted by fully-qualified names, including namespaces. If set to 
+# NO (the default), the class list will be sorted only by class name, 
+# not including the namespace part. 
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. 
+# Note: This option applies only to the class list, not to the 
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to 
+# do proper type resolution of all parameters of a function it will reject a 
+# match between the prototype and the implementation of a member function even 
+# if there is only one candidate or it is obvious which candidate to choose 
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen 
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or macro consists of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and macros in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. 
+# This will remove the Files entry from the Quick Index and from the 
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the 
+# Namespaces page.  This will remove the Namespaces entry from the Quick Index 
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that 
+# doxygen should invoke to get the current version for each file (typically from 
+# the version control system). Doxygen will invoke the program by executing (via 
+# popen()) the command <command> <input-file>, where <command> is the value of 
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
+# provided by doxygen. Whatever the program writes to standard output 
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    = 
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed 
+# by doxygen. The layout file controls the global structure of the generated 
+# output files in an output format independent way. To create the layout file 
+# that represents doxygen's defaults, run doxygen with the -l option. 
+# You can optionally specify a file name after the option, if omitted 
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE            = 
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files 
+# containing the references data. This must be a list of .bib files. The 
+# .bib extension is automatically appended if omitted. Using this command 
+# requires the bibtex tool to be installed. See also 
+# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style 
+# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this 
+# feature you need bibtex and perl available in the search path.
+
+CITE_BIB_FILES         = 
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for 
+# functions that are documented, but have no documentation for their parameters 
+# or return value. If set to NO (the default) doxygen will only warn about 
+# wrong or incomplete parameter documentation, but not about the absence of 
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text. Optionally the format may contain 
+# $version, which will be replaced by the version of the file (if it could 
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = 
+
+# This tag can be used to specify the character encoding of the source files 
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is 
+# also the default input encoding. Doxygen uses libiconv (or the iconv built 
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for 
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh 
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py 
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.d \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.i++ \
+                         *.inl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.idl \
+                         *.odl \
+                         *.cs \
+                         *.php \
+                         *.php3 \
+                         *.inc \
+                         *.m \
+                         *.markdown \
+                         *.md \
+                         *.mm \
+                         *.dox \
+                         *.py \
+                         *.f90 \
+                         *.f \
+                         *.for \
+                         *.vhd \
+                         *.vhdl
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag. 
+# Note that relative paths are relative to the directory from which doxygen is 
+# run.
+
+EXCLUDE                = utils/perfect_hash
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or 
+# directories that are symbolic links (a Unix file system feature) are excluded 
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories. Note that the wildcards are matched 
+# against the file with absolute path, so to exclude all test directories 
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = 
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 
+# (namespaces, classes, functions, etc.) that should be excluded from the 
+# output. The symbol name can be a fully qualified name, a word, or if the 
+# wildcard * is used, a substring. Examples: ANamespace, AClass, 
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.  If FILTER_PATTERNS is specified, this tag will be 
+# ignored.
+
+INPUT_FILTER           = 
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
+# basis.  Doxygen will compare the file name with each pattern and apply the 
+# filter if there is a match.  The filters are a list of the form: 
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
+# info on how filters are used. If FILTER_PATTERNS is empty or if 
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file 
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) 
+# and it is also possible to disable source filtering for a specific pattern 
+# using *.ext= (so without naming a filter). This option only has effect when 
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS = 
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources. 
+# Note: To get rid of all source code in the generated output, make sure also 
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C, C++ and Fortran comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) 
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from 
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will 
+# link to the source code.  Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code 
+# will point to the HTML generated by the htags(1) tool instead of doxygen 
+# built-in source browser. The htags tool is part of GNU's global source 
+# tagging system (see http://www.gnu.org/software/global/global.html). You 
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header. Note that when using a custom header you are responsible  
+# for the proper inclusion of any scripts and style sheets that doxygen 
+# needs, which is dependent on the configuration options used. 
+# It is advised to generate a default header using "doxygen -w html 
+# header.html footer.html stylesheet.css YourConfigFile" and then modify 
+# that header. Note that the header is subject to change so you typically 
+# have to redo this when upgrading to a newer version of doxygen or when 
+# changing the value of configuration settings such as GENERATE_TREEVIEW!
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet. Note that doxygen will try to copy 
+# the style sheet file to the HTML output directory, so don't put your own 
+# style sheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        = 
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or 
+# other source files which should be copied to the HTML output directory. Note 
+# that these files will be copied to the base HTML output directory. Use the 
+# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these 
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that 
+# the files will be copied as-is; there are no commands or markers available.
+
+HTML_EXTRA_FILES       = 
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. 
+# Doxygen will adjust the colors in the style sheet and background images 
+# according to this color. Hue is specified as an angle on a colorwheel, 
+# see http://en.wikipedia.org/wiki/Hue for more information. 
+# For instance the value 0 represents red, 60 is yellow, 120 is green, 
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. 
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of 
+# the colors in the HTML output. For a value of 0 the output will use 
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to 
+# the luminance component of the colors in the HTML output. Values below 
+# 100 gradually make the output lighter, whereas values above 100 make 
+# the output darker. The value divided by 100 is the actual gamma applied, 
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, 
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML 
+# page will contain the date and time when the page was generated. Setting 
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML 
+# documentation will contain sections that can be hidden and shown after the 
+# page has loaded.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of 
+# entries shown in the various tree structured indices initially; the user 
+# can expand and collapse entries dynamically later on. Doxygen will expand 
+# the tree to such a level that at most the specified number of entries are 
+# visible (unless a fully collapsed tree already exceeds this amount). 
+# So setting the number of entries 1 will produce a full collapsed tree by 
+# default. 0 is a special value representing an infinite number of entries 
+# and will result in a full expanded tree by default.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files 
+# will be generated that can be used as input for Apple's Xcode 3 
+# integrated development environment, introduced with OSX 10.5 (Leopard). 
+# To create a documentation set, doxygen will generate a Makefile in the 
+# HTML output directory. Running make will produce the docset in that 
+# directory and running "make install" will install the docset in 
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find 
+# it at startup. 
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html 
+# for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the 
+# feed. A documentation feed provides an umbrella under which multiple 
+# documentation sets from a single provider (such as a company or product suite) 
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that 
+# should uniquely identify the documentation set bundle. This should be a 
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen 
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify 
+# the documentation publisher. This should be a reverse domain-name style 
+# string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output directory.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING 
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file 
+# content.
+
+CHM_INDEX_ENCODING     = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and 
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated 
+# that can be used as input for Qt's qhelpgenerator to generate a 
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can 
+# be used to specify the file name of the resulting .qch file. 
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               = 
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating 
+# Qt Help Project output. For more information please see 
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating 
+# Qt Help Project output. For more information please see 
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to 
+# add. For more information please see 
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   = 
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the 
+# custom filter to add. For more information please see 
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> 
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  = 
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this 
+# project's 
+# filter section matches. 
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> 
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  = 
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can 
+# be used to specify the location of Qt's qhelpgenerator. 
+# If non-empty doxygen will try to run qhelpgenerator on the generated 
+# .qhp file.
+
+QHG_LOCATION           = 
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files  
+# will be generated, which together with the HTML files, form an Eclipse help 
+# plugin. To install this plugin and make it available under the help contents 
+# menu in Eclipse, the contents of the directory containing the HTML and XML 
+# files needs to be copied into the plugins directory of eclipse. The name of 
+# the directory within the plugins directory should be the same as 
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before 
+# the help appears.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin 
+# the directory name containing the HTML and XML files should also have 
+# this name.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) 
+# at top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it. Since the tabs have the same information as the 
+# navigation tree you can set this option to NO if you already set 
+# GENERATE_TREEVIEW to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index 
+# structure should be generated to display hierarchical information. 
+# If the tag value is set to YES, a side panel will be generated 
+# containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). 
+# Windows users are probably better off using the HTML help feature. 
+# Since the tree basically has the same information as the tab index you 
+# could consider to set DISABLE_INDEX to NO when enabling this option.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values 
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML 
+# documentation. Note that a value of 0 will completely suppress the enum 
+# values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open 
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of Latex formulas included 
+# as images in the HTML documentation. The default is 10. Note that 
+# when you change the font size after a successful doxygen run you need 
+# to manually remove any form_*.png images from the HTML output directory 
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images 
+# generated for formulas are transparent PNGs. Transparent PNGs are 
+# not supported properly for IE 6.0, but are supported on all modern browsers. 
+# Note that when changing this option you need to delete any form_*.png files 
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax 
+# (see http://www.mathjax.org) which uses client side Javascript for the 
+# rendering instead of using prerendered bitmaps. Use this if you do not 
+# have LaTeX installed or if you want to formulas look prettier in the HTML 
+# output. When enabled you may also need to install MathJax separately and 
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you need to specify the location relative to the 
+# HTML output directory using the MATHJAX_RELPATH option. The destination 
+# directory should contain the MathJax.js script. For instance, if the mathjax 
+# directory is located at the same level as the HTML output directory, then 
+# MATHJAX_RELPATH should be ../mathjax. The default value points to 
+# the MathJax Content Delivery Network so you can quickly see the result without 
+# installing MathJax.  However, it is strongly recommended to install a local 
+# copy of MathJax from http://www.mathjax.org before deployment.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension 
+# names that should be enabled during MathJax rendering.
+
+MATHJAX_EXTENSIONS     = 
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box 
+# for the HTML output. The underlying search engine uses javascript 
+# and DHTML and should work on any modern browser. Note that when using 
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets 
+# (GENERATE_DOCSET) there is already a search function so this one should 
+# typically be disabled. For large projects the javascript based search engine 
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be 
+# implemented using a PHP enabled web server instead of at the web client 
+# using Javascript. Doxygen will generate the search PHP script and index 
+# file to put on the web server. The advantage of the server 
+# based approach is that it scales better to large projects and allows 
+# full text search. The disadvantages are that it is more difficult to setup 
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name. 
+# Note that when enabling USE_PDFLATEX this option is only used for 
+# generating bitmaps for formulas in the HTML output, but not in the 
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for 
+# the generated latex document. The footer should contain everything after 
+# the last chapter. If it is left blank doxygen will generate a 
+# standard footer. Notice: only use this tag if you know what you are doing!
+
+LATEX_FOOTER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include 
+# source code with syntax highlighting in the LaTeX output. 
+# Note that which sources are shown also depends on other settings 
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the 
+# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See 
+# http://en.wikipedia.org/wiki/BibTeX for more info.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimized for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load style sheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assignments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
+# dump the program listings (including syntax highlighting 
+# and cross-referencing information) to the XML output. Note that 
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader.  This is useful 
+# if you want to understand what is going on.  On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# pointed to by INCLUDE_PATH will be searched when a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed. To prevent a macro definition from being 
+# undefined via #undef or recursively expanded use the := operator 
+# instead of the = operator.
+
+PREDEFINED             = 
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition that 
+# overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all references to function-like macros 
+# that are alone on a line, have an all uppercase name, and do not end with a 
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. For each 
+# tag file the location of the external documentation should be added. The 
+# format of a tag file without this location is as follows: 
+#   TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#   TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths 
+# or URLs. Note that each tag file must have a unique name (where the name does 
+# NOT include the path). If a tag file is not located in the directory in which 
+# doxygen is run, you must also specify the path to the tagfile here.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
+# or super classes. Setting the tag to NO turns the diagrams off. Note that 
+# this option also works with HAVE_DOT disabled, but it is recommended to 
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc 
+# command. Doxygen will then run the mscgen tool (see 
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the 
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where 
+# the mscgen tool resides. If left empty the tool is assumed to be found in the 
+# default search path.
+
+MSCGEN_PATH            = 
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is 
+# allowed to run in parallel. When set to 0 (the default) doxygen will 
+# base this on the number of processors available in the system. You can set it 
+# explicitly to a value larger than 0 to get control over the balance 
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS        = 0
+
+# By default doxygen will use the Helvetica font for all dot files that 
+# doxygen generates. When you want a differently looking font you can specify 
+# the font name using DOT_FONTNAME. You need to make sure dot is able to find 
+# the font, which can be done by putting it in a standard location or by setting 
+# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the 
+# directory containing the font.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. 
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the Helvetica font. 
+# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to 
+# set the path where dot can find it.
+
+DOT_FONTPATH           = 
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similar to the OMG's Unified Modeling 
+# Language.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside 
+# the class node. If there are many fields or methods and many nodes the 
+# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS 
+# threshold limits the number of items for each type to make the size more 
+# managable. Set this to 0 for no limit. Note that the threshold may be 
+# exceeded by 50% before the limit is enforced.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then 
+# doxygen will generate a call dependency graph for every global function 
+# or class method. Note that enabling this option will significantly increase 
+# the time of a run. So in most cases it will be better to enable call graphs 
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then 
+# doxygen will generate a caller dependency graph for every global function 
+# or class method. Note that enabling this option will significantly increase 
+# the time of a run. So in most cases it will be better to enable caller 
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES 
+# then doxygen will show the dependencies a directory has on other directories 
+# in a graphical way. The dependency relations are determined by the #include 
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are svg, png, jpg, or gif. 
+# If left blank png will be used. If you choose svg you need to set 
+# HTML_FILE_EXTENSION to xhtml in order to make the SVG files 
+# visible in IE 9+ (other browsers do not have this requirement).
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to 
+# enable generation of interactive SVG images that allow zooming and panning. 
+# Note that this requires a modern browser other than Internet Explorer. 
+# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you 
+# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files 
+# visible. Older versions of IE do not have SVG support.
+
+INTERACTIVE_SVG        = NO
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that 
+# contain msc files that are included in the documentation (see the 
+# \mscfile command).
+
+MSCFILE_DIRS           = 
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 
+# nodes that will be shown in the graph. If the number of nodes in a graph 
+# becomes larger than this value, doxygen will truncate the graph, which is 
+# visualized by representing a node as a red box. Note that doxygen if the 
+# number of direct children of the root node in a graph is already larger than 
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note 
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
+# graphs generated by dot. A depth value of 3 means that only nodes reachable 
+# from the root by following a path via at most 3 edges will be shown. Nodes 
+# that lay further from the root node will be omitted. Note that setting this 
+# option to 1 or 2 may greatly reduce the computation time needed for large 
+# code bases. Also note that the size of a graph can be further restricted by 
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
+# background. This is disabled by default, because dot on Windows does not 
+# seem to support this out of the box. Warning: Depending on the platform used, 
+# enabling this option may lead to badly anti-aliased labels on the edges of 
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
+# files in one run (i.e. multiple -o and -T options on the command line). This 
+# makes dot run faster, but since only newer versions of dot (>1.8.10) 
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES

+ 2 - 0
components/rtgui/SConscript

@@ -72,6 +72,8 @@ widgets/edit.c
 widgets/mv_view.c
 widgets/plot.c
 widgets/plot_curve.c
+widgets/digtube.c
+widgets/digfont.c
 """)
 
 if GetDepend('RTGUI_USING_FONT_COMPACT'):

+ 97 - 194
components/rtgui/common/asc12font.c

@@ -15,198 +15,101 @@
 
 const rt_uint8_t asc12_font[] =
 {
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81,
-    0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff,
-    0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00,
-    0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c,
-    0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18,
-    0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
-    0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x3c,
-    0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99,
-    0xc3, 0xff, 0xff, 0xff, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00,
-    0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30,
-    0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67,
-    0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00,
-    0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x06, 0x0e, 0x1e, 0x3e,
-    0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c,
-    0x18, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00,
-    0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0xc6, 0x60, 0x38, 0x6c,
-    0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe,
-    0xfe, 0xfe, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00,
-    0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
-    0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28,
-    0x6c, 0xfe, 0x6c, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe,
-    0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10,
-    0x10, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x48, 0x48, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x14, 0x28, 0x7c, 0x28, 0x7c, 0x28, 0x50, 0x50, 0x00, 0x00,
-    0x00, 0x10, 0x38, 0x40, 0x40, 0x38, 0x48, 0x70, 0x10, 0x10, 0x00, 0x00, 0x00, 0x20, 0x50, 0x20,
-    0x0c, 0x70, 0x08, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x20, 0x20, 0x54, 0x48,
-    0x34, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x00, 0x00, 0x20, 0x20, 0x10,
-    0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x00, 0x00, 0x10, 0x7c, 0x10, 0x28, 0x28, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0xfc, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x10, 0x30, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
-    0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x00, 0x00,
-    0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0x30, 0x10, 0x10,
-    0x10, 0x10, 0x10, 0x10, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x04, 0x08, 0x10, 0x20, 0x44,
-    0x7c, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x04, 0x18, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00,
-    0x00, 0x0c, 0x14, 0x14, 0x24, 0x44, 0x7c, 0x04, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x20, 0x20,
-    0x38, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x20, 0x40, 0x78, 0x44, 0x44, 0x44,
-    0x38, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x44, 0x04, 0x08, 0x08, 0x08, 0x10, 0x10, 0x00, 0x00, 0x00,
-    0x00, 0x38, 0x44, 0x44, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44,
-    0x44, 0x3c, 0x04, 0x08, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x30,
-    0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x30, 0x20, 0x00, 0x00,
-    0x00, 0x00, 0x0c, 0x10, 0x60, 0x80, 0x60, 0x10, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x7c, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0x18, 0x04, 0x18, 0x20,
-    0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x04, 0x08, 0x10, 0x00, 0x30, 0x00, 0x00, 0x00,
-    0x38, 0x44, 0x44, 0x4c, 0x54, 0x54, 0x4c, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, 0x30, 0x10, 0x28,
-    0x28, 0x28, 0x7c, 0x44, 0xec, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x44, 0x44, 0x78, 0x44, 0x44, 0x44,
-    0xf8, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, 0x40, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00,
-    0x00, 0xf0, 0x48, 0x44, 0x44, 0x44, 0x44, 0x48, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x44, 0x50,
-    0x70, 0x50, 0x40, 0x44, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x20, 0x28, 0x38, 0x28, 0x20, 0x20,
-    0x70, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, 0x40, 0x40, 0x4c, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00,
-    0x00, 0xec, 0x44, 0x44, 0x7c, 0x44, 0x44, 0x44, 0xec, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x10, 0x10,
-    0x10, 0x10, 0x10, 0x10, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x08, 0x08, 0x08, 0x48, 0x48, 0x48,
-    0x30, 0x00, 0x00, 0x00, 0x00, 0xec, 0x44, 0x48, 0x50, 0x70, 0x48, 0x44, 0xe4, 0x00, 0x00, 0x00,
-    0x00, 0x70, 0x20, 0x20, 0x20, 0x20, 0x24, 0x24, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xec, 0x6c, 0x6c,
-    0x54, 0x54, 0x44, 0x44, 0xec, 0x00, 0x00, 0x00, 0x00, 0xec, 0x64, 0x64, 0x54, 0x54, 0x54, 0x4c,
-    0xec, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00,
-    0x00, 0x78, 0x24, 0x24, 0x24, 0x38, 0x20, 0x20, 0x70, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44,
-    0x44, 0x44, 0x44, 0x44, 0x38, 0x1c, 0x00, 0x00, 0x00, 0xf8, 0x44, 0x44, 0x44, 0x78, 0x48, 0x44,
-    0xe0, 0x00, 0x00, 0x00, 0x00, 0x34, 0x4c, 0x40, 0x38, 0x04, 0x04, 0x64, 0x58, 0x00, 0x00, 0x00,
-    0x00, 0xfc, 0x90, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, 0x00, 0xec, 0x44, 0x44,
-    0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0xec, 0x44, 0x44, 0x28, 0x28, 0x28, 0x10,
-    0x10, 0x00, 0x00, 0x00, 0x00, 0xec, 0x44, 0x44, 0x54, 0x54, 0x54, 0x54, 0x28, 0x00, 0x00, 0x00,
-    0x00, 0xc4, 0x44, 0x28, 0x10, 0x10, 0x28, 0x44, 0xc4, 0x00, 0x00, 0x00, 0x00, 0xec, 0x44, 0x28,
-    0x28, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x44, 0x08, 0x10, 0x10, 0x20, 0x44,
-    0x7c, 0x00, 0x00, 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00,
-    0x00, 0x40, 0x20, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x38, 0x08, 0x08,
-    0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x10, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-    0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
-    0x44, 0x3c, 0x44, 0x44, 0x3c, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44,
-    0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, 0x40, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00,
-    0x00, 0x0c, 0x04, 0x34, 0x4c, 0x44, 0x44, 0x44, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
-    0x44, 0x7c, 0x40, 0x40, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x20, 0x7c, 0x20, 0x20, 0x20, 0x20,
-    0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x4c, 0x44, 0x44, 0x44, 0x3c, 0x04, 0x38, 0x00,
-    0x00, 0xc0, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44, 0xec, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x70,
-    0x10, 0x10, 0x10, 0x10, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x78, 0x08, 0x08, 0x08, 0x08,
-    0x08, 0x08, 0x70, 0x00, 0x00, 0xc0, 0x40, 0x5c, 0x48, 0x70, 0x50, 0x48, 0xdc, 0x00, 0x00, 0x00,
-    0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8,
-    0x54, 0x54, 0x54, 0x54, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x64, 0x44, 0x44, 0x44,
-    0xec, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0xd8, 0x64, 0x44, 0x44, 0x44, 0x78, 0x40, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x34,
-    0x4c, 0x44, 0x44, 0x44, 0x3c, 0x04, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x30, 0x20, 0x20, 0x20,
-    0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, 0x38, 0x04, 0x44, 0x78, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x20, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc,
-    0x44, 0x44, 0x44, 0x4c, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x44, 0x44, 0x28, 0x28,
-    0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x44, 0x54, 0x54, 0x54, 0x28, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0xcc, 0x48, 0x30, 0x30, 0x48, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec,
-    0x44, 0x24, 0x28, 0x18, 0x10, 0x10, 0x78, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x48, 0x10, 0x20, 0x44,
-    0x7c, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x10, 0x10, 0x20, 0x10, 0x10, 0x10, 0x08, 0x00,
-    0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x20, 0x10, 0x10,
-    0x10, 0x10, 0x08, 0x10, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x58, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*" ",0*/
+    0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00,0x00,/*"!",1*/
+    0x00,0x28,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*""",2*/
+    0x00,0x00,0x28,0x28,0xFC,0x28,0x50,0xFC,0x50,0x50,0x00,0x00,/*"#",3*/
+    0x00,0x20,0x78,0xA8,0xA0,0x60,0x30,0x28,0xA8,0xF0,0x20,0x00,/*"$",4*/
+    0x00,0x00,0x48,0xA8,0xB0,0x50,0x28,0x34,0x54,0x48,0x00,0x00,/*"%",5*/
+    0x00,0x00,0x20,0x50,0x50,0x78,0xA8,0xA8,0x90,0x6C,0x00,0x00,/*"&",6*/
+    0x00,0x40,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"'",7*/
+    0x00,0x04,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x08,0x04,0x00,/*"(",8*/
+    0x00,0x40,0x20,0x10,0x10,0x10,0x10,0x10,0x10,0x20,0x40,0x00,/*")",9*/
+    0x00,0x00,0x00,0x20,0xA8,0x70,0x70,0xA8,0x20,0x00,0x00,0x00,/*"*",10*/
+    0x00,0x00,0x20,0x20,0x20,0xF8,0x20,0x20,0x20,0x00,0x00,0x00,/*"+",11*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x80,/*",",12*/
+    0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,/*"-",13*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,/*".",14*/
+    0x00,0x08,0x10,0x10,0x10,0x20,0x20,0x40,0x40,0x40,0x80,0x00,/*"/",15*/
+    0x00,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00,/*"0",16*/
+    0x00,0x00,0x20,0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00,/*"1",17*/
+    0x00,0x00,0x70,0x88,0x88,0x10,0x20,0x40,0x80,0xF8,0x00,0x00,/*"2",18*/
+    0x00,0x00,0x70,0x88,0x08,0x30,0x08,0x08,0x88,0x70,0x00,0x00,/*"3",19*/
+    0x00,0x00,0x10,0x30,0x50,0x50,0x90,0x78,0x10,0x18,0x00,0x00,/*"4",20*/
+    0x00,0x00,0xF8,0x80,0x80,0xF0,0x08,0x08,0x88,0x70,0x00,0x00,/*"5",21*/
+    0x00,0x00,0x70,0x90,0x80,0xF0,0x88,0x88,0x88,0x70,0x00,0x00,/*"6",22*/
+    0x00,0x00,0xF8,0x90,0x10,0x20,0x20,0x20,0x20,0x20,0x00,0x00,/*"7",23*/
+    0x00,0x00,0x70,0x88,0x88,0x70,0x88,0x88,0x88,0x70,0x00,0x00,/*"8",24*/
+    0x00,0x00,0x70,0x88,0x88,0x88,0x78,0x08,0x48,0x70,0x00,0x00,/*"9",25*/
+    0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x20,0x00,0x00,/*":",26*/
+    0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x20,0x00,/*";",27*/
+    0x00,0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x00,0x00,/*"<",28*/
+    0x00,0x00,0x00,0x00,0xF8,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,/*"=",29*/
+    0x00,0x40,0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x40,0x00,0x00,/*">",30*/
+    0x00,0x00,0x70,0x88,0x88,0x10,0x20,0x20,0x00,0x20,0x00,0x00,/*"?",31*/
+    0x00,0x00,0x70,0x88,0x98,0xA8,0xA8,0xB8,0x80,0x78,0x00,0x00,/*"@",32*/
+    0x00,0x00,0x20,0x20,0x30,0x50,0x50,0x78,0x48,0xCC,0x00,0x00,/*"A",33*/
+    0x00,0x00,0xF0,0x48,0x48,0x70,0x48,0x48,0x48,0xF0,0x00,0x00,/*"B",34*/
+    0x00,0x00,0x78,0x88,0x80,0x80,0x80,0x80,0x88,0x70,0x00,0x00,/*"C",35*/
+    0x00,0x00,0xF0,0x48,0x48,0x48,0x48,0x48,0x48,0xF0,0x00,0x00,/*"D",36*/
+    0x00,0x00,0xF8,0x48,0x50,0x70,0x50,0x40,0x48,0xF8,0x00,0x00,/*"E",37*/
+    0x00,0x00,0xF8,0x48,0x50,0x70,0x50,0x40,0x40,0xE0,0x00,0x00,/*"F",38*/
+    0x00,0x00,0x38,0x48,0x80,0x80,0x9C,0x88,0x48,0x30,0x00,0x00,/*"G",39*/
+    0x00,0x00,0xCC,0x48,0x48,0x78,0x48,0x48,0x48,0xCC,0x00,0x00,/*"H",40*/
+    0x00,0x00,0xF8,0x20,0x20,0x20,0x20,0x20,0x20,0xF8,0x00,0x00,/*"I",41*/
+    0x00,0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x90,0xE0,0x00,/*"J",42*/
+    0x00,0x00,0xEC,0x48,0x50,0x60,0x50,0x50,0x48,0xEC,0x00,0x00,/*"K",43*/
+    0x00,0x00,0xE0,0x40,0x40,0x40,0x40,0x40,0x44,0xFC,0x00,0x00,/*"L",44*/
+    0x00,0x00,0xD8,0xD8,0xD8,0xD8,0xA8,0xA8,0xA8,0xA8,0x00,0x00,/*"M",45*/
+    0x00,0x00,0xDC,0x48,0x68,0x68,0x58,0x58,0x48,0xE8,0x00,0x00,/*"N",46*/
+    0x00,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00,/*"O",47*/
+    0x00,0x00,0xF0,0x48,0x48,0x70,0x40,0x40,0x40,0xE0,0x00,0x00,/*"P",48*/
+    0x00,0x00,0x70,0x88,0x88,0x88,0x88,0xE8,0x98,0x70,0x18,0x00,/*"Q",49*/
+    0x00,0x00,0xF0,0x48,0x48,0x70,0x50,0x48,0x48,0xEC,0x00,0x00,/*"R",50*/
+    0x00,0x00,0x78,0x88,0x80,0x60,0x10,0x08,0x88,0xF0,0x00,0x00,/*"S",51*/
+    0x00,0x00,0xF8,0xA8,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00,/*"T",52*/
+    0x00,0x00,0xCC,0x48,0x48,0x48,0x48,0x48,0x48,0x30,0x00,0x00,/*"U",53*/
+    0x00,0x00,0xCC,0x48,0x48,0x50,0x50,0x30,0x20,0x20,0x00,0x00,/*"V",54*/
+    0x00,0x00,0xA8,0xA8,0xA8,0x70,0x50,0x50,0x50,0x50,0x00,0x00,/*"W",55*/
+    0x00,0x00,0xD8,0x50,0x50,0x20,0x20,0x50,0x50,0xD8,0x00,0x00,/*"X",56*/
+    0x00,0x00,0xD8,0x50,0x50,0x20,0x20,0x20,0x20,0x70,0x00,0x00,/*"Y",57*/
+    0x00,0x00,0xF8,0x90,0x10,0x20,0x20,0x40,0x48,0xF8,0x00,0x00,/*"Z",58*/
+    0x00,0x38,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x38,0x00,/*"[",59*/
+    0x00,0x40,0x40,0x40,0x20,0x20,0x10,0x10,0x10,0x08,0x00,0x00,/*"\",60*/
+    0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x70,0x00,/*"]",61*/
+    0x00,0x20,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"^",62*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,/*"_",63*/
+    0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"`",64*/
+    0x00,0x00,0x00,0x00,0x00,0x30,0x48,0x38,0x48,0x3C,0x00,0x00,/*"a",65*/
+    0x00,0x00,0xC0,0x40,0x40,0x70,0x48,0x48,0x48,0x70,0x00,0x00,/*"b",66*/
+    0x00,0x00,0x00,0x00,0x00,0x38,0x48,0x40,0x40,0x38,0x00,0x00,/*"c",67*/
+    0x00,0x00,0x18,0x08,0x08,0x38,0x48,0x48,0x48,0x3C,0x00,0x00,/*"d",68*/
+    0x00,0x00,0x00,0x00,0x00,0x30,0x48,0x78,0x40,0x38,0x00,0x00,/*"e",69*/
+    0x00,0x00,0x1C,0x20,0x20,0x78,0x20,0x20,0x20,0x78,0x00,0x00,/*"f",70*/
+    0x00,0x00,0x00,0x00,0x00,0x3C,0x48,0x30,0x40,0x78,0x44,0x38,/*"g",71*/
+    0x00,0x00,0xC0,0x40,0x40,0x70,0x48,0x48,0x48,0xEC,0x00,0x00,/*"h",72*/
+    0x00,0x00,0x20,0x00,0x00,0x60,0x20,0x20,0x20,0x70,0x00,0x00,/*"i",73*/
+    0x00,0x00,0x10,0x00,0x00,0x30,0x10,0x10,0x10,0x10,0x10,0xE0,/*"j",74*/
+    0x00,0x00,0xC0,0x40,0x40,0x5C,0x50,0x70,0x48,0xEC,0x00,0x00,/*"k",75*/
+    0x00,0x00,0xE0,0x20,0x20,0x20,0x20,0x20,0x20,0xF8,0x00,0x00,/*"l",76*/
+    0x00,0x00,0x00,0x00,0x00,0xF0,0xA8,0xA8,0xA8,0xA8,0x00,0x00,/*"m",77*/
+    0x00,0x00,0x00,0x00,0x00,0xF0,0x48,0x48,0x48,0xEC,0x00,0x00,/*"n",78*/
+    0x00,0x00,0x00,0x00,0x00,0x30,0x48,0x48,0x48,0x30,0x00,0x00,/*"o",79*/
+    0x00,0x00,0x00,0x00,0x00,0xF0,0x48,0x48,0x48,0x70,0x40,0xE0,/*"p",80*/
+    0x00,0x00,0x00,0x00,0x00,0x38,0x48,0x48,0x48,0x38,0x08,0x1C,/*"q",81*/
+    0x00,0x00,0x00,0x00,0x00,0xD8,0x60,0x40,0x40,0xE0,0x00,0x00,/*"r",82*/
+    0x00,0x00,0x00,0x00,0x00,0x78,0x40,0x30,0x08,0x78,0x00,0x00,/*"s",83*/
+    0x00,0x00,0x00,0x20,0x20,0x70,0x20,0x20,0x20,0x18,0x00,0x00,/*"t",84*/
+    0x00,0x00,0x00,0x00,0x00,0xD8,0x48,0x48,0x48,0x3C,0x00,0x00,/*"u",85*/
+    0x00,0x00,0x00,0x00,0x00,0xEC,0x48,0x50,0x30,0x20,0x00,0x00,/*"v",86*/
+    0x00,0x00,0x00,0x00,0x00,0xA8,0xA8,0x70,0x50,0x50,0x00,0x00,/*"w",87*/
+    0x00,0x00,0x00,0x00,0x00,0xD8,0x50,0x20,0x50,0xD8,0x00,0x00,/*"x",88*/
+    0x00,0x00,0x00,0x00,0x00,0xEC,0x48,0x50,0x30,0x20,0x20,0xC0,/*"y",89*/
+    0x00,0x00,0x00,0x00,0x00,0x78,0x10,0x20,0x20,0x78,0x00,0x00,/*"z",90*/
+    0x00,0x18,0x10,0x10,0x10,0x20,0x10,0x10,0x10,0x10,0x18,0x00,/*"{",91*/
+    0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,/*"|",92*/
+    0x00,0x60,0x20,0x20,0x20,0x10,0x20,0x20,0x20,0x20,0x60,0x00,/*"}",93*/
+    0x40,0xA4,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"~",94*/
 };
 
 const struct rtgui_font_bitmap asc12 =
@@ -216,8 +119,8 @@ const struct rtgui_font_bitmap asc12 =
     RT_NULL,            /* offset for each character */
     6,                  /* width */
     12,                 /* height */
-    0,                  /* first char */
-    255                 /* last char */
+    32,                  /* first char */
+    127                 /* last char */
 };
 
 struct rtgui_font rtgui_font_asc12 =

+ 97 - 259
components/rtgui/common/asc16font.c

@@ -16,262 +16,101 @@
 #ifdef RTGUI_USING_FONT16
 const unsigned char asc16_font[] =
 {
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x6c, 0xfe, 0x6c, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
-    0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xd6, 0xd6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,
-    0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xfe, 0xee, 0x6c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x7c, 0x38, 0x38, 0x7c, 0x6c, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xfe, 0xc6, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc2, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00,
-    0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
-    0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
-    0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
-    0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xfe, 0xd6, 0xd6, 0xd6, 0xd6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
-    0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00,
-    0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-    0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-    0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x76, 0x36, 0x7e, 0xd8, 0xd8, 0x6e, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
-    0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x18, 0x18, 0x3c, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3c, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0xf8, 0xcc, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0xcc, 0xcc, 0xc6, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00,
-    0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
-    0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xdc, 0x86, 0x0c, 0x18, 0x3e, 0x00, 0x00,
-    0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x9e, 0x3e, 0x06, 0x06, 0x00, 0x00,
-    0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
-    0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
-    0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
-    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-    0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-    0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-    0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-    0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-    0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-    0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-    0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-    0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-    0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
-    0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*" ",0*/
+    0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x18,0x18,0x00,0x00,/*"!",1*/
+    0x00,0x12,0x36,0x24,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*""",2*/
+    0x00,0x00,0x00,0x24,0x24,0x24,0xFE,0x48,0x48,0x48,0xFE,0x48,0x48,0x48,0x00,0x00,/*"#",3*/
+    0x00,0x00,0x10,0x38,0x54,0x54,0x50,0x30,0x18,0x14,0x14,0x54,0x54,0x38,0x10,0x10,/*"$",4*/
+    0x00,0x00,0x00,0x44,0xA4,0xA8,0xA8,0xA8,0x54,0x1A,0x2A,0x2A,0x2A,0x44,0x00,0x00,/*"%",5*/
+    0x00,0x00,0x00,0x30,0x48,0x48,0x48,0x50,0x6E,0xA4,0x94,0x88,0x89,0x76,0x00,0x00,/*"&",6*/
+    0x00,0x60,0x60,0x20,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"'",7*/
+    0x00,0x02,0x04,0x08,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x08,0x08,0x04,0x02,0x00,/*"(",8*/
+    0x00,0x40,0x20,0x10,0x10,0x08,0x08,0x08,0x08,0x08,0x08,0x10,0x10,0x20,0x40,0x00,/*")",9*/
+    0x00,0x00,0x00,0x00,0x10,0x10,0xD6,0x38,0x38,0xD6,0x10,0x10,0x00,0x00,0x00,0x00,/*"*",10*/
+    0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0xFE,0x10,0x10,0x10,0x10,0x00,0x00,0x00,/*"+",11*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x20,0xC0,/*",",12*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"-",13*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00,/*".",14*/
+    0x00,0x00,0x01,0x02,0x02,0x04,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x00,/*"/",15*/
+    0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x24,0x18,0x00,0x00,/*"0",16*/
+    0x00,0x00,0x00,0x10,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00,/*"1",17*/
+    0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x04,0x04,0x08,0x10,0x20,0x42,0x7E,0x00,0x00,/*"2",18*/
+    0x00,0x00,0x00,0x3C,0x42,0x42,0x04,0x18,0x04,0x02,0x02,0x42,0x44,0x38,0x00,0x00,/*"3",19*/
+    0x00,0x00,0x00,0x04,0x0C,0x14,0x24,0x24,0x44,0x44,0x7E,0x04,0x04,0x1E,0x00,0x00,/*"4",20*/
+    0x00,0x00,0x00,0x7E,0x40,0x40,0x40,0x58,0x64,0x02,0x02,0x42,0x44,0x38,0x00,0x00,/*"5",21*/
+    0x00,0x00,0x00,0x1C,0x24,0x40,0x40,0x58,0x64,0x42,0x42,0x42,0x24,0x18,0x00,0x00,/*"6",22*/
+    0x00,0x00,0x00,0x7E,0x44,0x44,0x08,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,/*"7",23*/
+    0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x24,0x18,0x24,0x42,0x42,0x42,0x3C,0x00,0x00,/*"8",24*/
+    0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x26,0x1A,0x02,0x02,0x24,0x38,0x00,0x00,/*"9",25*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,/*":",26*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x20,/*";",27*/
+    0x00,0x00,0x00,0x02,0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x02,0x00,0x00,/*"<",28*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,/*"=",29*/
+    0x00,0x00,0x00,0x40,0x20,0x10,0x08,0x04,0x02,0x04,0x08,0x10,0x20,0x40,0x00,0x00,/*">",30*/
+    0x00,0x00,0x00,0x3C,0x42,0x42,0x62,0x02,0x04,0x08,0x08,0x00,0x18,0x18,0x00,0x00,/*"?",31*/
+    0x00,0x00,0x00,0x38,0x44,0x5A,0xAA,0xAA,0xAA,0xAA,0xB4,0x42,0x44,0x38,0x00,0x00,/*"@",32*/
+    0x00,0x00,0x00,0x10,0x10,0x18,0x28,0x28,0x24,0x3C,0x44,0x42,0x42,0xE7,0x00,0x00,/*"A",33*/
+    0x00,0x00,0x00,0xF8,0x44,0x44,0x44,0x78,0x44,0x42,0x42,0x42,0x44,0xF8,0x00,0x00,/*"B",34*/
+    0x00,0x00,0x00,0x3E,0x42,0x42,0x80,0x80,0x80,0x80,0x80,0x42,0x44,0x38,0x00,0x00,/*"C",35*/
+    0x00,0x00,0x00,0xF8,0x44,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x44,0xF8,0x00,0x00,/*"D",36*/
+    0x00,0x00,0x00,0xFC,0x42,0x48,0x48,0x78,0x48,0x48,0x40,0x42,0x42,0xFC,0x00,0x00,/*"E",37*/
+    0x00,0x00,0x00,0xFC,0x42,0x48,0x48,0x78,0x48,0x48,0x40,0x40,0x40,0xE0,0x00,0x00,/*"F",38*/
+    0x00,0x00,0x00,0x3C,0x44,0x44,0x80,0x80,0x80,0x8E,0x84,0x44,0x44,0x38,0x00,0x00,/*"G",39*/
+    0x00,0x00,0x00,0xE7,0x42,0x42,0x42,0x42,0x7E,0x42,0x42,0x42,0x42,0xE7,0x00,0x00,/*"H",40*/
+    0x00,0x00,0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00,/*"I",41*/
+    0x00,0x00,0x00,0x3E,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x88,0xF0,/*"J",42*/
+    0x00,0x00,0x00,0xEE,0x44,0x48,0x50,0x70,0x50,0x48,0x48,0x44,0x44,0xEE,0x00,0x00,/*"K",43*/
+    0x00,0x00,0x00,0xE0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x42,0xFE,0x00,0x00,/*"L",44*/
+    0x00,0x00,0x00,0xEE,0x6C,0x6C,0x6C,0x6C,0x54,0x54,0x54,0x54,0x54,0xD6,0x00,0x00,/*"M",45*/
+    0x00,0x00,0x00,0xC7,0x62,0x62,0x52,0x52,0x4A,0x4A,0x4A,0x46,0x46,0xE2,0x00,0x00,/*"N",46*/
+    0x00,0x00,0x00,0x38,0x44,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x44,0x38,0x00,0x00,/*"O",47*/
+    0x00,0x00,0x00,0xFC,0x42,0x42,0x42,0x42,0x7C,0x40,0x40,0x40,0x40,0xE0,0x00,0x00,/*"P",48*/
+    0x00,0x00,0x00,0x38,0x44,0x82,0x82,0x82,0x82,0x82,0xB2,0xCA,0x4C,0x38,0x06,0x00,/*"Q",49*/
+    0x00,0x00,0x00,0xFC,0x42,0x42,0x42,0x7C,0x48,0x48,0x44,0x44,0x42,0xE3,0x00,0x00,/*"R",50*/
+    0x00,0x00,0x00,0x3E,0x42,0x42,0x40,0x20,0x18,0x04,0x02,0x42,0x42,0x7C,0x00,0x00,/*"S",51*/
+    0x00,0x00,0x00,0xFE,0x92,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,/*"T",52*/
+    0x00,0x00,0x00,0xE7,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00,/*"U",53*/
+    0x00,0x00,0x00,0xE7,0x42,0x42,0x44,0x24,0x24,0x28,0x28,0x18,0x10,0x10,0x00,0x00,/*"V",54*/
+    0x00,0x00,0x00,0xD6,0x92,0x92,0x92,0x92,0xAA,0xAA,0x6C,0x44,0x44,0x44,0x00,0x00,/*"W",55*/
+    0x00,0x00,0x00,0xE7,0x42,0x24,0x24,0x18,0x18,0x18,0x24,0x24,0x42,0xE7,0x00,0x00,/*"X",56*/
+    0x00,0x00,0x00,0xEE,0x44,0x44,0x28,0x28,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,/*"Y",57*/
+    0x00,0x00,0x00,0x7E,0x84,0x04,0x08,0x08,0x10,0x20,0x20,0x42,0x42,0xFC,0x00,0x00,/*"Z",58*/
+    0x00,0x1E,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x1E,0x00,/*"[",59*/
+    0x00,0x00,0x40,0x40,0x20,0x20,0x10,0x10,0x10,0x08,0x08,0x04,0x04,0x04,0x02,0x02,/*"\",60*/
+    0x00,0x78,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x78,0x00,/*"]",61*/
+    0x00,0x1C,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"^",62*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,/*"_",63*/
+    0x00,0x60,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"`",64*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x1E,0x22,0x42,0x42,0x3F,0x00,0x00,/*"a",65*/
+    0x00,0x00,0x00,0xC0,0x40,0x40,0x40,0x58,0x64,0x42,0x42,0x42,0x64,0x58,0x00,0x00,/*"b",66*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x22,0x40,0x40,0x40,0x22,0x1C,0x00,0x00,/*"c",67*/
+    0x00,0x00,0x00,0x06,0x02,0x02,0x02,0x1E,0x22,0x42,0x42,0x42,0x26,0x1B,0x00,0x00,/*"d",68*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x7E,0x40,0x40,0x42,0x3C,0x00,0x00,/*"e",69*/
+    0x00,0x00,0x00,0x0F,0x11,0x10,0x10,0x7E,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00,/*"f",70*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x44,0x44,0x38,0x40,0x3C,0x42,0x42,0x3C,/*"g",71*/
+    0x00,0x00,0x00,0xC0,0x40,0x40,0x40,0x5C,0x62,0x42,0x42,0x42,0x42,0xE7,0x00,0x00,/*"h",72*/
+    0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00,/*"i",73*/
+    0x00,0x00,0x00,0x0C,0x0C,0x00,0x00,0x1C,0x04,0x04,0x04,0x04,0x04,0x04,0x44,0x78,/*"j",74*/
+    0x00,0x00,0x00,0xC0,0x40,0x40,0x40,0x4E,0x48,0x50,0x68,0x48,0x44,0xEE,0x00,0x00,/*"k",75*/
+    0x00,0x00,0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00,/*"l",76*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x49,0x49,0x49,0x49,0x49,0xED,0x00,0x00,/*"m",77*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xDC,0x62,0x42,0x42,0x42,0x42,0xE7,0x00,0x00,/*"n",78*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00,/*"o",79*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xD8,0x64,0x42,0x42,0x42,0x44,0x78,0x40,0xE0,/*"p",80*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x22,0x42,0x42,0x42,0x22,0x1E,0x02,0x07,/*"q",81*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEE,0x32,0x20,0x20,0x20,0x20,0xF8,0x00,0x00,/*"r",82*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x42,0x40,0x3C,0x02,0x42,0x7C,0x00,0x00,/*"s",83*/
+    0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x7C,0x10,0x10,0x10,0x10,0x10,0x0C,0x00,0x00,/*"t",84*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC6,0x42,0x42,0x42,0x42,0x46,0x3B,0x00,0x00,/*"u",85*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE7,0x42,0x24,0x24,0x28,0x10,0x10,0x00,0x00,/*"v",86*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xD7,0x92,0x92,0xAA,0xAA,0x44,0x44,0x00,0x00,/*"w",87*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6E,0x24,0x18,0x18,0x18,0x24,0x76,0x00,0x00,/*"x",88*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE7,0x42,0x24,0x24,0x28,0x18,0x10,0x10,0xE0,/*"y",89*/
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x44,0x08,0x10,0x10,0x22,0x7E,0x00,0x00,/*"z",90*/
+    0x00,0x03,0x04,0x04,0x04,0x04,0x04,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x03,0x00,/*"{",91*/
+    0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,/*"|",92*/
+    0x00,0x60,0x10,0x10,0x10,0x10,0x10,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x60,0x00,/*"}",93*/
+    0x30,0x4C,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"~",94*/
 };
 
 struct rtgui_font_bitmap asc16 =
@@ -281,8 +120,8 @@ struct rtgui_font_bitmap asc16 =
     RT_NULL,            /* offset for each character */
     8,                  /* width */
     16,                 /* height */
-    0,                  /* first char */
-    255                 /* last char */
+    32,                  /* first char */
+    127                 /* last char */
 };
 
 struct rtgui_font rtgui_font_asc16 =
@@ -294,5 +133,4 @@ struct rtgui_font rtgui_font_asc16 =
     &asc16,             /* font private data */
 };
 
-/* size = 4096 bytes */
 #endif

+ 0 - 7
components/rtgui/common/dc_hw.c

@@ -37,13 +37,6 @@ static rt_bool_t rtgui_dc_hw_fini(struct rtgui_dc *dc);
 static rt_bool_t rtgui_dc_hw_get_visible(struct rtgui_dc *dc);
 static void rtgui_dc_hw_get_rect(struct rtgui_dc *dc, rtgui_rect_t *rect);
 
-struct rtgui_dc_hw
-{
-    struct rtgui_dc parent;
-    rtgui_widget_t *owner;
-    const struct rtgui_graphic_driver *hw_driver;
-};
-
 const struct rtgui_dc_engine dc_hw_engine =
 {
     rtgui_dc_hw_draw_point,

+ 3 - 2
components/rtgui/common/font_bmp.c

@@ -59,11 +59,12 @@ void rtgui_bitmap_font_draw_char(struct rtgui_font_bitmap *font, struct rtgui_dc
 
     for (i = 0; i < h; i++)
     {
-        rt_uint8_t chr;
+        rt_uint8_t chr = 0;
         const rt_uint8_t *ptr = font_ptr + i * word_bytes;
         for (j = 0; j < w; j++)
         {
-            if (j % 8 == 0)chr = *ptr++;
+            if (j % 8 == 0)
+                chr = *ptr++;
             if (chr & 0x80)
                 rtgui_dc_draw_point(dc, j + x, i + y);
             else if (style & RTGUI_TEXTSTYLE_DRAW_BACKGROUND)

+ 2 - 0
components/rtgui/common/image_jpg.c

@@ -351,6 +351,7 @@ static rt_bool_t rtgui_image_jpeg_load(struct rtgui_image *image, struct rtgui_f
     {
         /* no memory */
         jpeg_finish_decompress(&jpeg->cinfo);
+        jpeg_destroy_decompress(&jpeg->cinfo);
         rt_free(jpeg);
 
         return RT_FALSE;
@@ -381,6 +382,7 @@ static void rtgui_image_jpeg_unload(struct rtgui_image *image)
             rtgui_filerw_close(jpeg->filerw);
             jpeg_finish_decompress(&jpeg->cinfo);
         }
+        jpeg_destroy_decompress(&jpeg->cinfo);
         rt_free(jpeg);
     }
 }

+ 10 - 0
components/rtgui/common/region.c

@@ -2274,3 +2274,13 @@ rt_bool_t rtgui_rect_is_empty(const rtgui_rect_t *rect)
     return RT_FALSE;
 }
 
+rtgui_rect_t *rtgui_rect_set(rtgui_rect_t *rect, int x, int y, int w, int h)
+{
+	RT_ASSERT(rect != RT_NULL);
+
+	rect->x1 = x; rect->y1 = y;
+	rect->x2 = x + w; rect->y2 = y + h;
+
+	return rect;
+}
+

+ 38 - 52
components/rtgui/common/rtgui_app.c

@@ -30,7 +30,6 @@ static void _rtgui_app_constructor(struct rtgui_app *app)
     app->ref_count      = 0;
     app->exit_code      = 0;
     app->tid            = RT_NULL;
-    app->server         = RT_NULL;
     app->mq             = RT_NULL;
     app->modal_object   = RT_NULL;
     app->main_object    = RT_NULL;
@@ -51,13 +50,13 @@ DEFINE_CLASS_TYPE(application, "application",
                   _rtgui_app_destructor,
                   sizeof(struct rtgui_app));
 
-struct rtgui_app *rtgui_app_create(
-    rt_thread_t tid,
-    const char *title)
+struct rtgui_app *rtgui_app_create(const char *title)
 {
-    rt_thread_t srv_tid;
+    rt_thread_t tid = rt_thread_self();
     struct rtgui_app *app;
+    struct rtgui_app *srv_app;
     struct rtgui_event_application event;
+    char mq_name[RT_NAME_MAX];
 
     RT_ASSERT(tid != RT_NULL);
     RT_ASSERT(title != RT_NULL);
@@ -70,10 +69,9 @@ struct rtgui_app *rtgui_app_create(
     /* one thread only can create one rtgui application */
     RT_ASSERT(tid->user_data == 0);
     app->tid = tid;
-    /* set user thread */
-    tid->user_data = (rt_uint32_t)app;
 
-    app->mq = rt_mq_create("rtgui", sizeof(union rtgui_event_generic), 32, RT_IPC_FLAG_FIFO);
+    rt_snprintf(mq_name, RT_NAME_MAX, "g%s", title);
+    app->mq = rt_mq_create(mq_name, sizeof(union rtgui_event_generic), 32, RT_IPC_FLAG_FIFO);
     if (app->mq == RT_NULL)
     {
         rt_kprintf("create msgq failed.\n");
@@ -85,31 +83,30 @@ struct rtgui_app *rtgui_app_create(
     if (app->name == RT_NULL)
         goto __err;
 
-    /* send a message to notify rtgui server */
-    srv_tid = rtgui_get_server();
-    if (srv_tid == RT_NULL)
+    /* the first app should be the server */
+    srv_app = rtgui_get_server();
+    if (srv_app == RT_NULL)
     {
-        rt_kprintf("gui server is not running.\n");
-        goto __err;
-    }
-
-    /* create the rtgui server application */
-    if (srv_tid == rt_thread_self())
+        /* set user thread */
+        tid->user_data = (rt_uint32_t)app;
+        rt_kprintf("RTGUI: creating the server app %p.\n", app);
         return app;
+    }
 
     RTGUI_EVENT_APP_CREATE_INIT(&event);
     event.app = app;
 
     /* notify rtgui server to one application has been created */
-    if (rtgui_send_sync(srv_tid, RTGUI_EVENT(&event), sizeof(event)) == RT_EOK)
+    if (rtgui_send_sync(srv_app, RTGUI_EVENT(&event), sizeof(event)) == RT_EOK)
     {
+        /* set user thread */
+        tid->user_data = (rt_uint32_t)app;
         return app;
     }
 
 __err:
 __mq_err:
     rtgui_object_destroy(RTGUI_OBJECT(app));
-    tid->user_data = 0;
     return RT_NULL;
 }
 RTM_EXPORT(rtgui_app_create);
@@ -124,7 +121,7 @@ RTM_EXPORT(rtgui_app_create);
 
 void rtgui_app_destroy(struct rtgui_app *app)
 {
-    rt_thread_t srv_tid;
+    struct rtgui_app *srv_app;
     _rtgui_application_check(app);
 
     if (!(app->state_flag & RTGUI_APP_FLAG_EXITED))
@@ -135,14 +132,14 @@ void rtgui_app_destroy(struct rtgui_app *app)
     }
 
     /* send a message to notify rtgui server */
-    srv_tid = rtgui_get_server();
-    if (srv_tid != rt_thread_self()) /* must not the server thread */
+    srv_app = rtgui_get_server();
+    if (srv_app != rtgui_app_self())
     {
         struct rtgui_event_application event;
         RTGUI_EVENT_APP_DESTROY_INIT(&event);
         event.app = app;
 
-        if (rtgui_send_sync(srv_tid, RTGUI_EVENT(&event), sizeof(event)) != RT_EOK)
+        if (rtgui_send_sync(srv_app, RTGUI_EVENT(&event), sizeof(event)) != RT_EOK)
         {
             rt_kprintf("destroy an application in server failed\n");
             return ;
@@ -168,25 +165,18 @@ struct rtgui_app *rtgui_app_self(void)
 }
 RTM_EXPORT(rtgui_app_self);
 
-void rtgui_app_set_onidle(rtgui_idle_func_t onidle)
+void rtgui_app_set_onidle(struct rtgui_app *app, rtgui_idle_func_t onidle)
 {
-    struct rtgui_app *app;
-
-    app = rtgui_app_self();
-    if (app != RT_NULL)
-        app->on_idle = onidle;
+    _rtgui_application_check(app);
+    app->on_idle = onidle;
 }
 RTM_EXPORT(rtgui_app_set_onidle);
 
-rtgui_idle_func_t rtgui_app_get_onidle(void)
+rtgui_idle_func_t rtgui_app_get_onidle(struct rtgui_app *app)
 {
-    struct rtgui_app *app;
 
-    app = rtgui_app_self();
-    if (app != RT_NULL)
-        return app->on_idle;
-    else
-        return RT_NULL;
+    _rtgui_application_check(app);
+    return app->on_idle;
 }
 RTM_EXPORT(rtgui_app_get_onidle);
 
@@ -369,7 +359,7 @@ void rtgui_app_activate(struct rtgui_app *app)
     RTGUI_EVENT_APP_ACTIVATE_INIT(&event);
     event.app = app;
 
-    rtgui_send(app->tid, RTGUI_EVENT(&event), sizeof(struct rtgui_event_application));
+    rtgui_send(app, RTGUI_EVENT(&event), sizeof(struct rtgui_event_application));
 }
 RTM_EXPORT(rtgui_app_activate);
 
@@ -380,28 +370,28 @@ void rtgui_app_close(struct rtgui_app *app)
     RTGUI_EVENT_APP_DESTROY_INIT(&event);
     event.app = app;
 
-    rtgui_send(app->tid, RTGUI_EVENT(&event), sizeof(struct rtgui_event_application));
+    rtgui_send(app, RTGUI_EVENT(&event), sizeof(struct rtgui_event_application));
 }
 RTM_EXPORT(rtgui_app_close);
 
 /**
  * set this application as window manager
  */
-rt_err_t rtgui_app_set_as_wm(void)
+rt_err_t rtgui_app_set_as_wm(struct rtgui_app *app)
 {
-    rt_thread_t srv_tid;
+    struct rtgui_app *srv_app;
     struct rtgui_event_set_wm event;
-    struct rtgui_app *app;
 
-    srv_tid = rtgui_get_server();
-    app = rtgui_app_self();
-    if (app != RT_NULL && srv_tid != RT_NULL)
+    _rtgui_application_check(app);
+
+    srv_app = rtgui_get_server();
+    if (srv_app != RT_NULL)
     {
         /* notify rtgui server, this is a window manager */
         RTGUI_EVENT_SET_WM_INIT(&event);
         event.app = app;
 
-        rtgui_send_sync(srv_tid, RTGUI_EVENT(&event), sizeof(event));
+        rtgui_send_sync(srv_app, RTGUI_EVENT(&event), sizeof(event));
         return RT_EOK;
     }
 
@@ -409,15 +399,11 @@ rt_err_t rtgui_app_set_as_wm(void)
 }
 RTM_EXPORT(rtgui_app_set_as_wm);
 
-void rtgui_app_set_main_win(struct rtgui_win *win)
+void rtgui_app_set_main_win(struct rtgui_app *app, struct rtgui_win *win)
 {
-    struct rtgui_app *app;
 
-    app = rtgui_app_self();
-    if (app != RT_NULL)
-    {
-        app->main_object = RTGUI_OBJECT(win);
-    }
+    _rtgui_application_check(app);
+    app->main_object = RTGUI_OBJECT(win);
 }
 RTM_EXPORT(rtgui_app_set_main_win);
 

+ 1 - 1
components/rtgui/common/rtgui_mv_model.c

@@ -422,7 +422,7 @@ static rt_bool_t _rtgui_mv_model_notify_view(struct rtgui_mv_model *model,
         struct rtgui_mv_view  *view,
         struct rtgui_event_mv_model *emodel)
 {
-    rt_thread_t target = RTGUI_WIDGET(view)->toplevel->app->tid;
+    struct rtgui_app *target = RTGUI_WIDGET(view)->toplevel->app;
     emodel->model = model;
     emodel->view = view;
     return rtgui_send(target, (struct rtgui_event *)emodel, sizeof(*emodel));

+ 17 - 43
components/rtgui/common/rtgui_system.c

@@ -70,7 +70,7 @@ static void rtgui_time_out(void *parameter)
 
     event.timer = timer;
 
-    rtgui_send(timer->tid, &(event.parent), sizeof(rtgui_event_timer_t));
+    rtgui_send(timer->app, &(event.parent), sizeof(rtgui_event_timer_t));
 }
 
 rtgui_timer_t *rtgui_timer_create(rt_int32_t time, rt_int32_t flag, rtgui_timeout_func timeout, void *parameter)
@@ -78,7 +78,7 @@ rtgui_timer_t *rtgui_timer_create(rt_int32_t time, rt_int32_t flag, rtgui_timeou
     rtgui_timer_t *timer;
 
     timer = (rtgui_timer_t *) rtgui_malloc(sizeof(rtgui_timer_t));
-    timer->tid = rt_thread_self();
+    timer->app = rtgui_app_self();
     timer->timeout = timeout;
     timer->user_data = parameter;
 
@@ -371,7 +371,7 @@ const char *event_string[] =
 
 #define DBG_MSG(x)  rt_kprintf x
 
-static void rtgui_event_dump(rt_thread_t tid, rtgui_event_t *event)
+static void rtgui_event_dump(struct rtgui_app* app, rtgui_event_t *event)
 {
     char *sender = "(unknown)";
 
@@ -389,12 +389,12 @@ static void rtgui_event_dump(rt_thread_t tid, rtgui_event_t *event)
 
     if (event->type >= RTGUI_EVENT_COMMAND)
     {
-        rt_kprintf("%s -- USER EVENT --> %s \n", sender, tid->name);
+        rt_kprintf("%s -- USER EVENT --> %s \n", sender, app->name);
         return ;
     }
     else
     {
-        rt_kprintf("%s -- %s --> %s ", sender, event_string[event->type], tid->name);
+        rt_kprintf("%s -- %s --> %s ", sender, event_string[event->type], app->name);
     }
 
     switch (event->type)
@@ -545,88 +545,68 @@ static void rtgui_event_dump(rt_thread_t tid, rtgui_event_t *event)
 }
 #else
 #define DBG_MSG(x)
-#define rtgui_event_dump(tid, event)
+#define rtgui_event_dump(app, event)
 #endif
 
 /************************************************************************/
 /* RTGUI IPC APIs                                                       */
 /************************************************************************/
-rt_err_t rtgui_send(rt_thread_t tid, rtgui_event_t *event, rt_size_t event_size)
+rt_err_t rtgui_send(struct rtgui_app* app, rtgui_event_t *event, rt_size_t event_size)
 {
     rt_err_t result;
-    struct rtgui_app *app;
 
-    RT_ASSERT(tid != RT_NULL);
+    RT_ASSERT(app != RT_NULL);
     RT_ASSERT(event != RT_NULL);
     RT_ASSERT(event_size != 0);
 
-    rtgui_event_dump(tid, event);
-
-    /* find struct rtgui_application */
-    app = (struct rtgui_app *)(tid->user_data);
-    if (app == RT_NULL)
-        return -RT_ERROR;
+    rtgui_event_dump(app, event);
 
     result = rt_mq_send(app->mq, event, event_size);
     if (result != RT_EOK)
     {
         if (event->type != RTGUI_EVENT_TIMER)
-            rt_kprintf("send event to %s failed\n", app->tid->name);
+            rt_kprintf("send event to %s failed\n", app->name);
     }
 
     return result;
 }
 RTM_EXPORT(rtgui_send);
 
-rt_err_t rtgui_send_urgent(rt_thread_t tid, rtgui_event_t *event, rt_size_t event_size)
+rt_err_t rtgui_send_urgent(struct rtgui_app* app, rtgui_event_t *event, rt_size_t event_size)
 {
     rt_err_t result;
-    struct rtgui_app *app;
 
-    RT_ASSERT(tid != RT_NULL);
+    RT_ASSERT(app != RT_NULL);
     RT_ASSERT(event != RT_NULL);
     RT_ASSERT(event_size != 0);
 
-    rtgui_event_dump(tid, event);
-
-    /* find rtgui_application */
-    app = (struct rtgui_app *)(tid->user_data);
-    if (app == RT_NULL)
-        return -RT_ERROR;
+    rtgui_event_dump(app, event);
 
     result = rt_mq_urgent(app->mq, event, event_size);
     if (result != RT_EOK)
-        rt_kprintf("send ergent event failed\n");
+        rt_kprintf("send ergent event to %s failed\n", app->name);
 
     return result;
 }
 RTM_EXPORT(rtgui_send_urgent);
 
-rt_err_t rtgui_send_sync(rt_thread_t tid, rtgui_event_t *event, rt_size_t event_size)
+rt_err_t rtgui_send_sync(struct rtgui_app* app, rtgui_event_t *event, rt_size_t event_size)
 {
     rt_err_t r;
-    struct rtgui_app *app;
     rt_int32_t ack_buffer, ack_status;
     struct rt_mailbox ack_mb;
 
-    RT_ASSERT(tid != RT_NULL);
+    RT_ASSERT(app != RT_NULL);
     RT_ASSERT(event != RT_NULL);
     RT_ASSERT(event_size != 0);
 
-    rtgui_event_dump(tid, event);
+    rtgui_event_dump(app, event);
 
     /* init ack mailbox */
     r = rt_mb_init(&ack_mb, "ack", &ack_buffer, 1, 0);
     if (r != RT_EOK)
         goto __return;
 
-    app = (struct rtgui_app *)(tid->user_data);
-    if (app == RT_NULL)
-    {
-        r = -RT_ERROR;
-        goto __return;
-    }
-
     event->ack = &ack_mb;
     r = rt_mq_send(app->mq, event, event_size);
     if (r != RT_EOK)
@@ -728,12 +708,6 @@ rt_err_t rtgui_recv_filter(rt_uint32_t type, rtgui_event_t *event, rt_size_t eve
 }
 RTM_EXPORT(rtgui_recv_filter);
 
-rt_thread_t rtgui_get_server(void)
-{
-    return rt_thread_find("rtgui");
-}
-RTM_EXPORT(rtgui_get_server);
-
 void rtgui_set_mainwin_rect(struct rtgui_rect *rect)
 {
     _mainwin_rect = *rect;

+ 13 - 10
components/rtgui/common/rtgui_theme.c

@@ -96,31 +96,34 @@ void rtgui_theme_draw_win(struct rtgui_topwin *win)
     if (!(win->flag & WINTITLE_NO))
     {
         rt_uint32_t index;
-        float r, g, b, delta;
+        rt_uint16_t r, g, b, delta;
 
+#define RGB_FACTOR  4
         if (win->flag & WINTITLE_ACTIVATE)
         {
-            r = 10;
-            g = 36;
-            b = 106;
-            delta = 150 / (float)(rect.x2 - rect.x1);
+            r = 10 << RGB_FACTOR;
+            g = 36 << RGB_FACTOR;
+            b = 106 << RGB_FACTOR;
+            delta = (150 << RGB_FACTOR) / (rect.x2 - rect.x1);
         }
         else
         {
-            r = 128;
-            g = 128;
-            b = 128;
-            delta = 64 / (float)(rect.x2 - rect.x1);
+            r = 128 << RGB_FACTOR;
+            g = 128 << RGB_FACTOR;
+            b = 128 << RGB_FACTOR;
+            delta = (64 << RGB_FACTOR) / (rect.x2 - rect.x1);
         }
 
-        RTGUI_WIDGET_FOREGROUND(win->title) = RTGUI_RGB(r, g, b);
         for (index = rect.x1; index < rect.x2 + 1; index ++)
         {
+            RTGUI_WIDGET_FOREGROUND(win->title) = RTGUI_RGB((r>>RGB_FACTOR), \
+                     (g>>RGB_FACTOR), (b>>RGB_FACTOR));
             rtgui_dc_draw_vline(dc, index, rect.y1, rect.y2);
             r += delta;
             g += delta;
             b += delta;
         }
+#undef RGB_FACTOR
 
         if (win->flag & WINTITLE_ACTIVATE)
         {

+ 69 - 0
components/rtgui/doc/ANNOUNCE.0.6.md

@@ -0,0 +1,69 @@
+RTGUI 0.6版发布纪要
+
+# 为什么是 0.6?
+
+RTGUI 是作为 RT-Thread 的一个组件存在的。这次新发布的版本是在原 RTGUI 基础上重
+构而来的。原 RTGUI 没有独立的版本号。暂设其为 0.5。所以本版本号取 0.6,为在原有
+基础上改进之意。以后我们会每个月发布一个新版本。下一个版本号会是 0.6.1。
+
+# 运行环境
+
+理论上原来可以运行 RTGUI 的设备上都可以运行新的 RTGUI。本版本自带一个 Windows
+模拟器,用来方便地评估运行效果。默认的运行环境是 realtouch。RT-Thread 中的模拟
+器也是可以运作的。
+
+# 新版本有什么特点?
+
+0. 新版本的 GUI 摒弃了原有的 workbench/view/window 的工作方式。转换成全面向
+   window的工作方式。原有的 workbench/view 可以用 notebook 来实现。
+0. 用 `rtgui_app` 对线程进行了抽象。
+0. 事件驱动更彻底:
+    0. 将事件处理机制集成进 `rtgui_object`。
+    0. 添加了`RTGUI_EVENT_SHOW` 和 `RTGUI_EVENT_HIDE` 来通知控件将要被显示/隐藏。
+    0. 底层代码中对事件的应用更加彻底。
+0. 重构了自动布局方式。使得控件的摆放更加方便。
+
+# 增强
+
+- 添加了 TJPGD 引擎。使得小内存系统解码 jpeg 图片成为可能。(onelife)
+- 添加了对单色屏的支持(onelife)
+- bmp 图像引擎的重构(onelife)
+- bmp 图像的旋转/缩放,以及功能性增强(amsl)
+- 增加屏幕快照功能(amsl)
+- PNG 引擎增加 Alpha 通道支持(amsl)
+- 新增 edit 多行文本编辑控件。(amsl)
+- 增加了 Model/View 的编程框架。(Grissiom)
+- 添加了缩减字库的特性,开启后可以自动添加用到的汉字,不用的汉字字形不会加入到
+  字库当中。使得 GUI 能够在小 ROM 系统上得以应用。(Grissiom)
+- 新增 digtube 七段码显示控件(prife)
+- demo/benchmark 新增了 FPS 输出(amsl)
+- 新增 box/panel/groupbox,支持自动布局(Bernard)
+
+# API 变化
+
+除了 workbench/view 的消失以外,还有如下的 API 变化:
+
+- c05a301, 68e3e30: `rtgui_{menu,win}_hiden` 被重命名为 `rtgui_{menu,win}_hide`。
+- 05e4894: 将 `struct rtgui_widget` 中的 `mini_{height,width}` 重命名为 `min_{height,width}`。
+- 等等……
+
+今后很长时间内,新版本的 RTGUI 会与此版本的 API 尽量只增不减,保持兼容。
+
+# Bug fixes
+
+- 00a6690: 解决了 `rtgui_notebook_set_current_by_index` 中重绘标签页的 bug。感
+  谢 prife 提交 bug 信息和补丁。
+- 6850ff2: 解决了 `last_mevent_widget` 引起的事件传送失败。感谢 heryon 提交bug
+  报告。
+- 9143e11: 解决了 jpeg 引擎中的内存泄漏。感谢 Young 提供 bug 信息。
+- fbd567c: 解决了 `rtgui_textbox_set_line_length` 的 bug。
+- 9b67b66: 修复了窗口标题栏渐变效果的绘制。
+- fc3abbf: 修复了 `rtgui_label_set_text`。感谢 tanghong668 提供 bug 信息。
+- d41586c: 修复了窗口激活时重复刷新的问题。感谢 onelife 提供 bug 信息。
+- ab08de6: 修复了字库缓存的 bug。感谢 rtt\_fans 提供 bug 信息。
+- 等等……
+
+除了上面提到的,luoyuncong2012, lgnq, shaolin 也有贡献。上面的列表也必然是不完
+整的。感谢编写了第一版 RTGUI 的 Bernard 和其他大侠们,没有他们的辛勤劳动,也不
+会有今天的版本。感谢各位使用和支持RTGUI的开发人员,是你们 RTGUI 体现了 RTGUI 的
+价值。

+ 0 - 0
components/rtgui/doc/road_map.txt → components/rtgui/doc/historical/road_map.txt


+ 81 - 0
components/rtgui/doc/mv-model.dox

@@ -0,0 +1,81 @@
+/** @~english
+  @page pg-mv-model Model-View framework
+
+  @brief A overview of the Model-View framework
+
+  @section Glossary
+
+  @li view: widget dedicated to show the data. It could be a graph, list etc.
+  @li model: abstraction and combination of data.
+  @li data: things that needed to be delivered or shown. It could be a array of
+  votage values which is sampled from a AD in an interval. Or it could be the
+  attributes of all the files in a folder.
+
+  @section Design considerations and implementations
+
+  @li one model can respond to more than one views. one view can connect to
+  more than one models.
+  @li It is guaranteed that the change events of a model will be sent to all
+  the registered views.
+  @li Because there are so many formats of data, Model-View neither specify the
+  format data is stored nor try to abstract them. The only thing stored in
+  model is a pointer to the underlaying data. It is the responsibility of
+  inherited classed to implement the boxing/un-boxing operations.
+  @li Data can be multi-dimensional. The "dimension" does not only means
+  dimension geometry. It can also means attributes. For example, a folder could
+  have two attributes which are name and icon. So it's two-dimensional. If take
+  the size into consideration, it will be three-dimensional. The size of
+  dimension is saved in model. Each dimension is correspond to a pointer to some
+  sort of data. Model can save many of them. As above, model does not make
+  assumptions on the underlaying data structure. It only provide mechanism, not
+  policy and leave that to the inherited classes.
+
+  @section Events
+
+  @li model has a record of registered views. When data changes, model notify
+  views the change by sending events. The event contains the id of the model,
+  the id of target view, the scope of changed data.
+  @li views can handle the event by retrieve data from model, and update
+  themselves according to the scope that data has changed. The connected model
+  views should have the same presentation of data structure. Views should also
+  restore all the models it interested. In the case of repainting, it should
+  re-retrieve data from those models.
+  @li model send events by rtgui_send. So it's suitable for the synchronization
+  between threads and even could be used in ISR.
+*/
+
+/** @~chinese
+  @page pg-mv-model Model-View 框架
+
+  @brief 对于 Model-View 框架的简介
+
+  @section 名词解释
+
+  @li view:用于显示数据的控件。可以是诸如图表控件、列表控件的控件。
+  @li model:对于数据的组合和抽象。
+  @li 数据:需要显示或传递的数据。它可以是每隔一段时间就从AD读取的电压值,也可
+  以是一个目录下所有文件的属性列表。
+
+  @section 设计原则和实现
+
+  @li 一个 model 可以对应多个view。一个view可以对应多个 model。
+  @li 保证 model 的更新事件会同时发送到所有注册的 view 上。
+  @li 因为数据的形式与内容千差万别,所以 Model-View 不规定数据的存储形式,也不对其进
+  行抽象。只在 model 中保留指向第一个数据的指针。打包/解包由从m odel/view 派生出
+  的子类实现。
+  @li 数据源可以是多维的。这里的维度指的不只是几何的维度,而且可以是属性。比如
+  一个目录,它可以有名称、图标两个属性,那么它就是两维的。如果加入大小这个属性
+  ,就是三维的。 model 内部存储数据的维度大小。一个维度对应一个数据首地址的指针
+  。model 中可以存储多个数据首地址。model 对底层数据结构不作假设。只提供机制,不
+  提供策略。只保证能够多维,但把具体的实现方式留给子类实现。
+
+  @subsection 事件
+
+  @li model 内部记录对自己感兴趣的 view。在数据变化时,用事件通知所有相关 view。事
+  件内容包含:自己的 id;目标 view 的 id;所变化数据的 index 范围。
+  @li view 收到事件之后通过 model id 拿到数据并根据事件中的变化范围更新自己。对于
+  指针的数据类型转换需要自己实现并保证和 model 一致。view 内部保存与自己相关的
+  model id,在需要重绘的时候要从所有相关 model 提取数据。
+  @li model 通过 rtgui_send 给 view 发送事件。使得这个模型适用于线程间同步,也
+  可以在中断上下文里通知事件的发生。
+*/

+ 8 - 0
components/rtgui/include/rtgui/dc.h

@@ -60,6 +60,14 @@ struct rtgui_dc
     const struct rtgui_dc_engine *engine;
 };
 
+/* hardware device context */
+struct rtgui_dc_hw
+{
+	struct rtgui_dc parent;
+	rtgui_widget_t *owner;
+	const struct rtgui_graphic_driver *hw_driver;
+};
+
 #define RTGUI_DC_FC(dc)         (rtgui_dc_get_gc(dc)->foreground)
 #define RTGUI_DC_BC(dc)         (rtgui_dc_get_gc(dc)->background)
 #define RTGUI_DC_FONT(dc)       (rtgui_dc_get_gc(dc)->font)

+ 34 - 3
components/rtgui/include/rtgui/driver.h

@@ -17,6 +17,7 @@
 #include <rtgui/list.h>
 #include <rtgui/color.h>
 
+/* graphic driver operations */
 struct rtgui_graphic_driver_ops
 {
     /* set and get pixel in (x, y) */
@@ -30,6 +31,22 @@ struct rtgui_graphic_driver_ops
     void (*draw_raw_hline)(rt_uint8_t *pixels, int x1, int x2, int y);
 };
 
+/* graphic extension operations */
+struct rtgui_graphic_ext_ops
+{
+	/* some 2D operations */
+	void (*draw_line)(rtgui_color_t *c, int x1, int y1, int x2, int y2);
+
+	void (*draw_rect)(rtgui_color_t *c, int x1, int y1, int x2, int y2);
+	void (*fill_rect)(rtgui_color_t *c, int x1, int y1, int x2, int y2);
+
+	void (*draw_circle)(rtgui_color_t *c, int x, int y, int r);
+	void (*fill_circle)(rtgui_color_t *c, int x, int y, int r);
+
+	void (*draw_ellipse)(rtgui_color_t *c, int x, int y, int rx, int ry);
+	void (*fill_ellipse)(rtgui_color_t *c, int x, int y, int rx, int ry);
+};
+
 struct rtgui_graphic_driver
 {
     /* pixel format and byte per pixel */
@@ -43,12 +60,12 @@ struct rtgui_graphic_driver
 
     /* framebuffer address and ops */
     volatile rt_uint8_t *framebuffer;
-    rt_device_t device;
+    struct rt_device* device;
+
     const struct rtgui_graphic_driver_ops *ops;
+	const struct rtgui_graphic_ext_ops *ext_ops;
 };
 
-void rtgui_graphic_driver_add(const struct rtgui_graphic_driver *driver);
-
 struct rtgui_graphic_driver *rtgui_graphic_driver_get_default(void);
 
 void rtgui_graphic_driver_get_rect(const struct rtgui_graphic_driver *driver, rtgui_rect_t *rect);
@@ -64,5 +81,19 @@ rt_inline struct rtgui_graphic_driver *rtgui_graphic_get_device()
     return &_driver;
 }
 
+#ifdef RTGUI_USING_HW_CURSOR
+/*
+ * hardware cursor
+ */
+enum rtgui_cursor_type
+{
+	RTGUI_CURSOR_ARROW,
+	RTGUI_CURSOR_HAND,
+};
+
+void rtgui_cursor_set_device(const char* device_name);
+void rtgui_cursor_set_position(rt_uint16_t x, rt_uint16_t y);
+void rtgui_cursor_set_image(enum rtgui_cursor_type type);
 #endif
 
+#endif

+ 4 - 2
components/rtgui/include/rtgui/event.h

@@ -90,7 +90,7 @@ struct rtgui_event
     rt_uint16_t user;
 
     /* the event sender */
-    rt_thread_t sender;
+    struct rtgui_app *sender;
 
     /* mailbox to acknowledge request */
     rt_mailbox_t ack;
@@ -98,11 +98,13 @@ struct rtgui_event
 typedef struct rtgui_event rtgui_event_t;
 #define RTGUI_EVENT(e)  ((struct rtgui_event*)(e))
 
+extern struct rtgui_app* rtgui_app_self(void);
+
 #define RTGUI_EVENT_INIT(e, t)  do      \
 {                                       \
     (e)->type = (t);                    \
     (e)->user = 0;                      \
-    (e)->sender = rt_thread_self();     \
+    (e)->sender = rtgui_app_self();     \
     (e)->ack = RT_NULL;                 \
 } while (0)
 

+ 56 - 55
components/rtgui/include/rtgui/region.h

@@ -20,81 +20,82 @@
 extern "C" {
 #endif
 
-    typedef struct rtgui_region_data rtgui_region_data_t;
+typedef struct rtgui_region_data rtgui_region_data_t;
 
-    struct rtgui_region_data
-    {
-        rt_uint32_t size;
-        rt_uint32_t numRects;
-        /* XXX: And why, exactly, do we have this bogus struct definition? */
-        /* rtgui_rect_t rects[size]; in memory but not explicitly declared */
-    };
+struct rtgui_region_data
+{
+    rt_uint32_t size;
+    rt_uint32_t numRects;
+    /* XXX: And why, exactly, do we have this bogus struct definition? */
+    /* rtgui_rect_t rects[size]; in memory but not explicitly declared */
+};
 
-    typedef struct rtgui_region
-    {
-        rtgui_rect_t          extents;
-        rtgui_region_data_t  *data;
-    } rtgui_region_t;
+typedef struct rtgui_region
+{
+    rtgui_rect_t          extents;
+    rtgui_region_data_t  *data;
+} rtgui_region_t;
 
-    typedef enum
-    {
-        RTGUI_REGION_STATUS_FAILURE,
-        RTGUI_REGION_STATUS_SUCCESS
-    } rtgui_region_status_t;
+typedef enum
+{
+    RTGUI_REGION_STATUS_FAILURE,
+    RTGUI_REGION_STATUS_SUCCESS
+} rtgui_region_status_t;
 
-    /* creation/destruction */
+/* creation/destruction */
 
-    void rtgui_region_init(rtgui_region_t *region);
-    void rtgui_region_init_rect(rtgui_region_t *region,
-                                int x, int y, unsigned int width, unsigned int height);
-    void rtgui_region_init_with_extents(rtgui_region_t *region, const rtgui_rect_t *extents);
-    void rtgui_region_fini(rtgui_region_t *region);
+void rtgui_region_init(rtgui_region_t *region);
+void rtgui_region_init_rect(rtgui_region_t *region,
+                            int x, int y, unsigned int width, unsigned int height);
+void rtgui_region_init_with_extents(rtgui_region_t *region, const rtgui_rect_t *extents);
+void rtgui_region_fini(rtgui_region_t *region);
 
-    void rtgui_region_translate(rtgui_region_t *region, int x, int y);
+void rtgui_region_translate(rtgui_region_t *region, int x, int y);
 
-    rtgui_region_status_t rtgui_region_copy(rtgui_region_t *dest, rtgui_region_t *source);
+rtgui_region_status_t rtgui_region_copy(rtgui_region_t *dest, rtgui_region_t *source);
 
-    rtgui_region_status_t rtgui_region_intersect(rtgui_region_t *newReg, rtgui_region_t *reg1, rtgui_region_t *reg2);
-    rtgui_region_status_t rtgui_region_intersect_rect(rtgui_region_t *newReg, rtgui_region_t *reg1, rtgui_rect_t *rect);
-    rtgui_region_status_t rtgui_region_union(rtgui_region_t *newReg, rtgui_region_t *reg1, rtgui_region_t *reg2);
-    rtgui_region_status_t rtgui_region_union_rect(rtgui_region_t *dest, rtgui_region_t *source, rtgui_rect_t *rect);
-    rtgui_region_status_t rtgui_region_subtract(rtgui_region_t *regD, rtgui_region_t *regM, rtgui_region_t *regS);
-    rtgui_region_status_t rtgui_region_subtract_rect(rtgui_region_t *regD, rtgui_region_t *regM, rtgui_rect_t *rect);
-    rtgui_region_status_t rtgui_region_inverse(rtgui_region_t *newReg, rtgui_region_t *reg1, rtgui_rect_t *invRect);
+rtgui_region_status_t rtgui_region_intersect(rtgui_region_t *newReg, rtgui_region_t *reg1, rtgui_region_t *reg2);
+rtgui_region_status_t rtgui_region_intersect_rect(rtgui_region_t *newReg, rtgui_region_t *reg1, rtgui_rect_t *rect);
+rtgui_region_status_t rtgui_region_union(rtgui_region_t *newReg, rtgui_region_t *reg1, rtgui_region_t *reg2);
+rtgui_region_status_t rtgui_region_union_rect(rtgui_region_t *dest, rtgui_region_t *source, rtgui_rect_t *rect);
+rtgui_region_status_t rtgui_region_subtract(rtgui_region_t *regD, rtgui_region_t *regM, rtgui_region_t *regS);
+rtgui_region_status_t rtgui_region_subtract_rect(rtgui_region_t *regD, rtgui_region_t *regM, rtgui_rect_t *rect);
+rtgui_region_status_t rtgui_region_inverse(rtgui_region_t *newReg, rtgui_region_t *reg1, rtgui_rect_t *invRect);
 
-    int rtgui_region_num_rects(rtgui_region_t *region);
+int rtgui_region_num_rects(rtgui_region_t *region);
 
-    rtgui_rect_t *rtgui_region_rects(rtgui_region_t *region);
+rtgui_rect_t *rtgui_region_rects(rtgui_region_t *region);
 
 #define RTGUI_REGION_OUT    0
 #define RTGUI_REGION_IN     1
 #define RTGUI_REGION_PART   2
 
-    int rtgui_region_contains_point(rtgui_region_t *region, int x, int y, rtgui_rect_t *box);
-    int rtgui_region_contains_rectangle(rtgui_region_t *rtgui_region_t, rtgui_rect_t *prect);
+int rtgui_region_contains_point(rtgui_region_t *region, int x, int y, rtgui_rect_t *box);
+int rtgui_region_contains_rectangle(rtgui_region_t *rtgui_region_t, rtgui_rect_t *prect);
 
-    int rtgui_region_not_empty(rtgui_region_t *region);
-    rtgui_rect_t *rtgui_region_extents(rtgui_region_t *region);
+int rtgui_region_not_empty(rtgui_region_t *region);
+rtgui_rect_t *rtgui_region_extents(rtgui_region_t *region);
 
-    rtgui_region_status_t rtgui_region_append(rtgui_region_t *dest, rtgui_region_t *region);
-    rtgui_region_status_t rtgui_region_validate(rtgui_region_t *badreg, int *pOverlap);
+rtgui_region_status_t rtgui_region_append(rtgui_region_t *dest, rtgui_region_t *region);
+rtgui_region_status_t rtgui_region_validate(rtgui_region_t *badreg, int *pOverlap);
 
-    void rtgui_region_reset(rtgui_region_t *region, rtgui_rect_t *rect);
-    void rtgui_region_empty(rtgui_region_t *region);
-    void rtgui_region_dump(rtgui_region_t *region);
-    int rtgui_region_is_flat(rtgui_region_t *region);
+void rtgui_region_reset(rtgui_region_t *region, rtgui_rect_t *rect);
+void rtgui_region_empty(rtgui_region_t *region);
+void rtgui_region_dump(rtgui_region_t *region);
+int rtgui_region_is_flat(rtgui_region_t *region);
 
-    /* rect functions */
-    extern rtgui_rect_t rtgui_empty_rect;
+/* rect functions */
+extern rtgui_rect_t rtgui_empty_rect;
 
-    void rtgui_rect_moveto(rtgui_rect_t *rect, int x, int y);
-    void rtgui_rect_moveto_align(rtgui_rect_t *rect, rtgui_rect_t *to, int align);
-    void rtgui_rect_inflate(rtgui_rect_t *rect, int d);
-    void rtgui_rect_intersect(rtgui_rect_t *src, rtgui_rect_t *dest);
-    int  rtgui_rect_contains_point(const rtgui_rect_t *rect, int x, int y);
-    int  rtgui_rect_is_intersect(const rtgui_rect_t *rect1, const rtgui_rect_t *rect2);
-    int  rtgui_rect_is_equal(const rtgui_rect_t *rect1, const rtgui_rect_t *rect2);
-    rt_bool_t rtgui_rect_is_empty(const rtgui_rect_t *rect);
+void rtgui_rect_moveto(rtgui_rect_t *rect, int x, int y);
+void rtgui_rect_moveto_align(rtgui_rect_t *rect, rtgui_rect_t *to, int align);
+void rtgui_rect_inflate(rtgui_rect_t *rect, int d);
+void rtgui_rect_intersect(rtgui_rect_t *src, rtgui_rect_t *dest);
+int  rtgui_rect_contains_point(const rtgui_rect_t *rect, int x, int y);
+int  rtgui_rect_is_intersect(const rtgui_rect_t *rect1, const rtgui_rect_t *rect2);
+int  rtgui_rect_is_equal(const rtgui_rect_t *rect1, const rtgui_rect_t *rect2);
+rtgui_rect_t *rtgui_rect_set(rtgui_rect_t *rect, int x, int y, int w, int h);
+rt_bool_t rtgui_rect_is_empty(const rtgui_rect_t *rect);
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }

+ 5 - 0
components/rtgui/include/rtgui/rtgui.h

@@ -17,6 +17,11 @@
 #include <rtthread.h>
 #include <rtgui/rtgui_config.h>
 
+#define RTGUI_VERSION          0L        /**< major version number */
+#define RTGUI_SUBVERSION       6L        /**< minor version number */
+#define RTGUI_REVISION         0L        /**< revise version number */
+#define RTGUI_CODENAME         "Newton"  /**< code name */
+
 #define RT_INT16_MAX        32767
 #define RT_INT16_MIN        (-RT_INT16_MAX-1)
 #define RTGUI_NOT_FOUND     (-1)

+ 14 - 9
components/rtgui/include/rtgui/rtgui_app.h

@@ -52,9 +52,6 @@ struct rtgui_app
 
     /* the thread id */
     rt_thread_t tid;
-    /* the RTGUI server id */
-    rt_thread_t server;
-
     /* the message queue of thread */
     rt_mq_t mq;
     /* event buffer */
@@ -70,9 +67,13 @@ struct rtgui_app
 };
 
 /**
- * create an application named @myname on thread @param tid
+ * create an application named @myname on current thread.
+ *
+ * @param name the name of the application
+ *
+ * @return a pointer to struct rtgui_app on success. RT_NULL on failure.
  */
-struct rtgui_app *rtgui_app_create(rt_thread_t tid, const char *title);
+struct rtgui_app *rtgui_app_create(const char *name);
 void rtgui_app_destroy(struct rtgui_app *app);
 rt_bool_t rtgui_app_event_handler(struct rtgui_object *obj, rtgui_event_t *event);
 
@@ -81,11 +82,15 @@ void rtgui_app_exit(struct rtgui_app *app, rt_uint16_t code);
 void rtgui_app_activate(struct rtgui_app *app);
 void rtgui_app_close(struct rtgui_app *app);
 
-void rtgui_app_set_onidle(rtgui_idle_func_t onidle);
-rtgui_idle_func_t rtgui_app_get_onidle(void);
+void rtgui_app_set_onidle(struct rtgui_app *app, rtgui_idle_func_t onidle);
+rtgui_idle_func_t rtgui_app_get_onidle(struct rtgui_app *app);
+
+/**
+ * return the rtgui_app struct on current thread
+ */
 struct rtgui_app *rtgui_app_self(void);
 
-rt_err_t rtgui_app_set_as_wm(void);
-void rtgui_app_set_main_win(struct rtgui_win *win);
+rt_err_t rtgui_app_set_as_wm(struct rtgui_app *app);
+void rtgui_app_set_main_win(struct rtgui_app *app, struct rtgui_win *win);
 
 #endif /* end of include guard: __RTGUI_APP_H__ */

+ 2 - 2
components/rtgui/include/rtgui/rtgui_server.h

@@ -56,8 +56,8 @@ struct rtgui_topwin
     /* the window id */
     struct rtgui_win *wid;
 
-    /* the thread id */
-    rt_thread_t tid;
+    /* which app I belong */
+    struct rtgui_app *app;
 
     /* the extent information */
     rtgui_rect_t extent;

+ 6 - 6
components/rtgui/include/rtgui/rtgui_system.h

@@ -26,8 +26,8 @@ typedef void (*rtgui_timeout_func)(struct rtgui_timer *timer, void *parameter);
 
 struct rtgui_timer
 {
-    /* context thread id */
-    rt_thread_t tid;
+    /* the rtgui application it runs on */
+    struct rtgui_app* app;
     /* rt timer */
     struct rt_timer timer;
 
@@ -58,7 +58,7 @@ void *rtgui_realloc(void *ptr, rt_size_t size);
 #define rtgui_exit_critical     rt_exit_critical
 #endif
 
-rt_thread_t rtgui_get_server(void);
+struct rtgui_app* rtgui_get_server(void);
 void rtgui_set_mainwin_rect(struct rtgui_rect *rect);
 void rtgui_get_mainwin_rect(struct rtgui_rect *rect);
 void rtgui_get_screen_rect(struct rtgui_rect *rect);
@@ -67,9 +67,9 @@ void rtgui_screen_lock(rt_int32_t timeout);
 void rtgui_screen_unlock(void);
 
 struct rtgui_event;
-rt_err_t rtgui_send(rt_thread_t tid, struct rtgui_event *event, rt_size_t event_size);
-rt_err_t rtgui_send_urgent(rt_thread_t tid, struct rtgui_event *event, rt_size_t event_size);
-rt_err_t rtgui_send_sync(rt_thread_t tid, struct rtgui_event *event, rt_size_t event_size);
+rt_err_t rtgui_send(struct rtgui_app* app, struct rtgui_event *event, rt_size_t event_size);
+rt_err_t rtgui_send_urgent(struct rtgui_app* app, struct rtgui_event *event, rt_size_t event_size);
+rt_err_t rtgui_send_sync(struct rtgui_app* app, struct rtgui_event *event, rt_size_t event_size);
 rt_err_t rtgui_ack(struct rtgui_event *event, rt_int32_t status);
 rt_err_t rtgui_recv(struct rtgui_event *event, rt_size_t event_size);
 rt_err_t rtgui_recv_nosuspend(struct rtgui_event *event, rt_size_t event_size);

+ 36 - 0
components/rtgui/include/rtgui/widgets/digfont.h

@@ -0,0 +1,36 @@
+#ifndef DIG_FONT_H
+#define DIG_FONT_H
+
+struct rtgui_digitfont_data
+{
+    rt_uint16_t x;
+    rt_uint16_t y;
+    rt_uint16_t len;
+    rt_uint16_t type; //ˮƽºÍ´¹Ö±
+};
+
+struct rtgui_digitfont
+{
+    int seg1_len;
+    int seg1_hspace;
+    int seg1_vspace;
+    int seg1_nr; //9
+
+    int seg2_len;
+
+    int seg3_len;
+    struct rtgui_digitfont_data *data;
+};
+
+
+typedef struct rtgui_digitfont rtgui_digitfont_t;
+
+extern struct rtgui_digitfont digitfont_40;
+extern const char digtube_code_table[];
+
+int rtgui_digitfont_create(struct rtgui_digitfont *font);
+int rtgui_dc_draw_digitfont(struct rtgui_dc *dc, struct rtgui_digitfont *font, rtgui_rect_t *rect);
+int rtgui_get_digfont_metrics(struct rtgui_digitfont * font, rtgui_rect_t * rect);
+int rtgui_dc_draw_digitfont_code(struct rtgui_dc *dc, struct rtgui_digitfont * font, rtgui_rect_t * rect, char code);
+
+#endif

+ 68 - 0
components/rtgui/include/rtgui/widgets/digtube.h

@@ -0,0 +1,68 @@
+/*
+ * File      : digfont.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2012-12-21     pife         first version
+ */
+#ifndef __RTGUI_DIGTUBE_H__
+#define __RTGUI_DIGTUBE_H__
+
+#include <rtgui/rtgui.h>
+#include <rtgui/rtgui_system.h>
+#include <rtgui/widgets/widget.h>
+#include <rtgui/widgets/digfont.h>
+
+DECLARE_CLASS_TYPE(digtube);
+
+/** Gets the type of a digit tubes */
+#define RTGUI_DIGTUBE_TYPE       (RTGUI_TYPE(digtube))
+/** Casts the object to an rtgui_digtube */
+#define RTGUI_DIGTUBE(obj)       (RTGUI_OBJECT_CAST((obj), RTGUI_DIGTUBE_TYPE, rtgui_digtube_t))
+/** Checks if the object is an rtgui_digtube */
+#define RTGUI_IS_DIGTUBE(obj)    (RTGUI_OBJECT_CHECK_TYPE((obj), RTGUI_DIGTUBE_TYPE))
+
+/*
+ * the digit tube widget
+ */
+struct rtgui_digtube
+{
+    struct rtgui_widget parent;
+
+    struct rtgui_digitfont digitfont;
+
+    /* number of tubes */
+    rt_uint8_t tube_count;
+    rt_uint8_t tube_style;
+    rt_uint8_t digit_hight;
+    rt_uint8_t digit_width;
+    rt_uint8_t digit_space;
+    rtgui_color_t digit_bc;
+    void * value; 
+};
+typedef struct rtgui_digtube rtgui_digtube_t;
+
+rtgui_digtube_t *rtgui_digtube_create( struct rtgui_digitfont * digitfont, int count, void * value, int style);
+void rtgui_digtube_destroy(rtgui_digtube_t *digtube);
+
+rt_bool_t rtgui_digtube_event_handler(struct rtgui_object *object, struct rtgui_event *event);
+
+#define RTGUI_DIGTUBE_DEFAULT_BC         RTGUI_RGB(0, 0, 0)
+#define RTGUI_DIGTUBE_DEFAULT_FC         RTGUI_RGB(0xFF, 0, 0)
+#define RTGUI_DIGTUBE_DEFAULT_DIGIT_BC   RTGUI_RGB(100, 100, 100)
+
+#define RTGUI_DIGTUBE_DEFAULT_SPACE      10
+
+#define RTGUI_DIGTUBE_STYLE_NOBACKFONT   0x01
+#define RTGUI_DIGTUBE_STYLE_DISHEXNUM    0x02
+#define RTGUI_DIGTUBE_STYLE_DISCODES     0x04
+
+//void rtgui_digtube_set_text(rtgui_digtube_t *digtube, const char *text);
+//char *rtgui_digtube_get_text(rtgui_digtube_t *digtube);
+#endif

+ 1 - 1
components/rtgui/include/rtgui/widgets/menu.h

@@ -72,7 +72,7 @@ void rtgui_menu_set_onmenupop(struct rtgui_menu *menu, rtgui_event_handler_ptr h
 void rtgui_menu_set_onmenuhide(struct rtgui_menu *menu, rtgui_event_handler_ptr handler);
 
 void rtgui_menu_pop(struct rtgui_menu *menu, int x, int y);
-void rtgui_menu_hiden(struct rtgui_menu *menu);
+void rtgui_menu_hide(struct rtgui_menu *menu);
 
 #endif
 

+ 20 - 2
components/rtgui/include/rtgui/widgets/textbox.h

@@ -34,6 +34,8 @@ DECLARE_CLASS_TYPE(textbox);
 #define RTGUI_TEXTBOX_DEFAULT_WIDTH     80
 #define RTGUI_TEXTBOX_DEFAULT_HEIGHT        20
 
+#define RTGUI_TEXTBOX_BORDER_WIDTH     1
+
 #define RTGUI_TEXTBOX_SINGLE        0x00
 #define RTGUI_TEXTBOX_MULTI         0x01 /* multiline */
 #define RTGUI_TEXTBOX_MASK          0x02 /* ciphertext */
@@ -52,10 +54,13 @@ struct rtgui_textbox
 	rt_uint32_t flag;
 
 	/* current line and position */
-	rt_uint16_t line, line_begin, position, line_length;
+	rt_uint16_t line, line_begin, position;
+    /** maximum chars a line could hold excluding the NULL byte */
+    rt_uint16_t line_length;
 	rt_uint16_t dis_length; /*may be display length.*/
 	rt_uint16_t first_pos;
 	char mask_char;
+    /** a NULL terminated string that the textbox is holding */
 	char *text;
 	rt_size_t font_width;
 
@@ -77,7 +82,20 @@ void rtgui_textbox_set_value(struct rtgui_textbox *box, const char *text);
 const char *rtgui_textbox_get_value(struct rtgui_textbox *box);
 void rtgui_textbox_set_mask_char(rtgui_textbox_t *box, const char ch);
 char rtgui_textbox_get_mask_char(rtgui_textbox_t *box);
-void rtgui_textbox_set_line_length(struct rtgui_textbox *box, rt_size_t length);
+/** set the maximum chars a line could hold excluding the NULL byte
+ *
+ * It will truncate the current line if the length is smaller than the chars
+ * the box is currently holding. But the box->text is guaranteed to be NULL
+ * terminated anyway.
+ *
+ * @param box the text box it operate on
+ * @param length the new line length. It should be greater than 0.
+ *
+ * @return -RT_ERROR on invalid length; -RT_ENOMEM if there is no enough memory
+ * to allocate the new buffer. On returning -RT_ENOMEM, the original text would
+ * remain unchanged.
+ */
+rt_err_t rtgui_textbox_set_line_length(struct rtgui_textbox *box, rt_size_t length);
 
 void rtgui_textbox_get_edit_rect(struct rtgui_textbox *box, rtgui_rect_t *rect);
 

+ 106 - 107
components/rtgui/include/rtgui/widgets/widget.h

@@ -62,139 +62,138 @@ extern "C" {
 #define RTGUI_WIDGET_DC_SET_UNVISIBLE(w) RTGUI_WIDGET_FLAG(w) &= ~RTGUI_WIDGET_FLAG_DC_VISIBLE
 #define RTGUI_WIDGET_DC(w)              ((struct rtgui_dc*)&((w)->dc_type))
 
-    DECLARE_CLASS_TYPE(widget);
+DECLARE_CLASS_TYPE(widget);
 
-    /** Gets the type of a widget */
+/** Gets the type of a widget */
 #define RTGUI_WIDGET_TYPE       (RTGUI_TYPE(widget))
-    /** Casts the object to a rtgui_widget */
+/** Casts the object to a rtgui_widget */
 #define RTGUI_WIDGET(obj)       (RTGUI_OBJECT_CAST((obj), RTGUI_WIDGET_TYPE, rtgui_widget_t))
-    /** Check if the object is a rtgui_widget */
+/** Check if the object is a rtgui_widget */
 #define RTGUI_IS_WIDGET(obj)    (RTGUI_OBJECT_CHECK_TYPE((obj), RTGUI_WIDGET_TYPE))
 
-    /*
-     * the base widget object
-     */
-    struct rtgui_widget
-    {
-        /* inherit from rtgui_object */
-        struct rtgui_object object;
-
-        /* the widget that contains this widget */
-        struct rtgui_widget *parent;
-        /* the window that contains this widget */
-        struct rtgui_win *toplevel;
-        /* the widget children and sibling */
-        rtgui_list_t sibling;
-
-        /* widget flag */
-        rt_int32_t flag;
-
-        /* hardware device context */
-        rt_uint32_t dc_type;
-        const struct rtgui_dc_engine *dc_engine;
-
-        /* the graphic context of widget */
-        rtgui_gc_t gc;
-
-        /* the widget extent */
-        rtgui_rect_t extent;
-
-        /* minimal width and height of widget */
-        rt_int16_t mini_width, mini_height;
-        /* widget align */
-        rt_int32_t align;
-        rt_uint16_t border;
-        rt_uint16_t border_style;
-        /* the rect clip */
-        rtgui_region_t clip;
-
-        /* call back */
-        rt_bool_t (*on_focus_in)(struct rtgui_object *widget, struct rtgui_event *event);
-        rt_bool_t (*on_focus_out)(struct rtgui_object *widget, struct rtgui_event *event);
+/*
+ * the base widget object
+ */
+struct rtgui_widget
+{
+    /* inherit from rtgui_object */
+    struct rtgui_object object;
+
+    /* the widget that contains this widget */
+    struct rtgui_widget *parent;
+    /* the window that contains this widget */
+    struct rtgui_win *toplevel;
+    /* the widget children and sibling */
+    rtgui_list_t sibling;
+
+    /* widget flag */
+    rt_int32_t flag;
+
+    /* hardware device context */
+    rt_uint32_t dc_type;
+    const struct rtgui_dc_engine *dc_engine;
+
+    /* the graphic context of widget */
+    rtgui_gc_t gc;
+
+    /* the widget extent */
+    rtgui_rect_t extent;
+
+    /* minimal width and height of widget */
+    rt_int16_t min_width, min_height;
+    /* widget align */
+    rt_int32_t align;
+    rt_uint16_t border;
+    rt_uint16_t border_style;
+    /* the rect clip */
+    rtgui_region_t clip;
+
+    /* call back */
+    rt_bool_t (*on_focus_in)(struct rtgui_object *widget, struct rtgui_event *event);
+    rt_bool_t (*on_focus_out)(struct rtgui_object *widget, struct rtgui_event *event);
 #ifndef RTGUI_USING_SMALL_SIZE
-        rt_bool_t (*on_draw)(struct rtgui_object *widget, struct rtgui_event *event);
-        rt_bool_t (*on_mouseclick)(struct rtgui_object *widget, struct rtgui_event *event);
-        rt_bool_t (*on_key)(struct rtgui_object *widget, struct rtgui_event *event);
-        rt_bool_t (*on_size)(struct rtgui_object *widget, struct rtgui_event *event);
-        rt_bool_t (*on_command)(struct rtgui_object *widget, struct rtgui_event *event);
+    rt_bool_t (*on_draw)(struct rtgui_object *widget, struct rtgui_event *event);
+    rt_bool_t (*on_mouseclick)(struct rtgui_object *widget, struct rtgui_event *event);
+    rt_bool_t (*on_key)(struct rtgui_object *widget, struct rtgui_event *event);
+    rt_bool_t (*on_size)(struct rtgui_object *widget, struct rtgui_event *event);
+    rt_bool_t (*on_command)(struct rtgui_object *widget, struct rtgui_event *event);
 #endif
 
-        /* user private data */
-        rt_uint32_t user_data;
-    };
-    typedef struct rtgui_widget rtgui_widget_t;
+    /* user private data */
+    rt_uint32_t user_data;
+};
+typedef struct rtgui_widget rtgui_widget_t;
 
-    rtgui_widget_t *rtgui_widget_create(rtgui_type_t *widget_type);
-    void rtgui_widget_destroy(rtgui_widget_t *widget);
+rtgui_widget_t *rtgui_widget_create(rtgui_type_t *widget_type);
+void rtgui_widget_destroy(rtgui_widget_t *widget);
 
-    rt_bool_t rtgui_widget_event_handler(struct rtgui_object *object, rtgui_event_t *event);
+rt_bool_t rtgui_widget_event_handler(struct rtgui_object *object, rtgui_event_t *event);
 
-    /* focus and unfocus */
-    void rtgui_widget_focus(rtgui_widget_t *widget);
-    void rtgui_widget_unfocus(rtgui_widget_t *widget);
+/* focus and unfocus */
+void rtgui_widget_focus(rtgui_widget_t *widget);
+void rtgui_widget_unfocus(rtgui_widget_t *widget);
 
-    /* event handler for each command */
-    void rtgui_widget_set_onfocus(rtgui_widget_t *widget, rtgui_event_handler_ptr handler);
-    void rtgui_widget_set_onunfocus(rtgui_widget_t *widget, rtgui_event_handler_ptr handler);
+/* event handler for each command */
+void rtgui_widget_set_onfocus(rtgui_widget_t *widget, rtgui_event_handler_ptr handler);
+void rtgui_widget_set_onunfocus(rtgui_widget_t *widget, rtgui_event_handler_ptr handler);
 #ifndef RTGUI_USING_SMALL_SIZE
-    void rtgui_widget_set_ondraw(rtgui_widget_t *widget, rtgui_event_handler_ptr handler);
-    void rtgui_widget_set_onmouseclick(rtgui_widget_t *widget, rtgui_event_handler_ptr handler);
-    void rtgui_widget_set_onkey(rtgui_widget_t *widget, rtgui_event_handler_ptr handler);
-    void rtgui_widget_set_onsize(rtgui_widget_t *widget, rtgui_event_handler_ptr handler);
-    void rtgui_widget_set_oncommand(rtgui_widget_t *widget, rtgui_event_handler_ptr handler);
+void rtgui_widget_set_ondraw(rtgui_widget_t *widget, rtgui_event_handler_ptr handler);
+void rtgui_widget_set_onmouseclick(rtgui_widget_t *widget, rtgui_event_handler_ptr handler);
+void rtgui_widget_set_onkey(rtgui_widget_t *widget, rtgui_event_handler_ptr handler);
+void rtgui_widget_set_onsize(rtgui_widget_t *widget, rtgui_event_handler_ptr handler);
+void rtgui_widget_set_oncommand(rtgui_widget_t *widget, rtgui_event_handler_ptr handler);
 #endif
 
-    /* get and set rect of widget */
-    void rtgui_widget_get_rect(rtgui_widget_t *widget, rtgui_rect_t *rect);
-    void rtgui_widget_set_border(rtgui_widget_t *widget, rt_uint32_t style);
-    void rtgui_widget_set_rect(rtgui_widget_t *widget, const rtgui_rect_t *rect);
-    void rtgui_widget_set_rectangle(rtgui_widget_t *widget, int x, int y, int width, int height);
-    void rtgui_widget_get_extent(rtgui_widget_t *widget, rtgui_rect_t *rect);
+/* get and set rect of widget */
+void rtgui_widget_get_rect(rtgui_widget_t *widget, rtgui_rect_t *rect);
+void rtgui_widget_set_border(rtgui_widget_t *widget, rt_uint32_t style);
+void rtgui_widget_set_rect(rtgui_widget_t *widget, const rtgui_rect_t *rect);
+void rtgui_widget_set_rectangle(rtgui_widget_t *widget, int x, int y, int width, int height);
+void rtgui_widget_get_extent(rtgui_widget_t *widget, rtgui_rect_t *rect);
 
-#ifndef RTGUI_USING_SMALL_SIZE
-    void rtgui_widget_set_miniwidth(rtgui_widget_t *widget, int width);
-    void rtgui_widget_set_miniheight(rtgui_widget_t *widget, int height);
-#endif
+void rtgui_widget_set_minsize(rtgui_widget_t *widget, int width, int height);
+void rtgui_widget_set_minwidth(rtgui_widget_t *widget, int width);
+void rtgui_widget_set_minheight(rtgui_widget_t *widget, int height);
 
-    void rtgui_widget_set_parent(rtgui_widget_t *widget, rtgui_widget_t *parent);
+void rtgui_widget_set_parent(rtgui_widget_t *widget, rtgui_widget_t *parent);
 
-    /* get the physical position of a logic point on widget */
-    void rtgui_widget_point_to_device(rtgui_widget_t *widget, rtgui_point_t *point);
-    /* get the physical position of a logic rect on widget */
-    void rtgui_widget_rect_to_device(rtgui_widget_t *widget, rtgui_rect_t *rect);
+/* get the physical position of a logic point on widget */
+void rtgui_widget_point_to_device(rtgui_widget_t *widget, rtgui_point_t *point);
+/* get the physical position of a logic rect on widget */
+void rtgui_widget_rect_to_device(rtgui_widget_t *widget, rtgui_rect_t *rect);
 
-    /* get the logic position of a physical point on widget */
-    void rtgui_widget_point_to_logic(rtgui_widget_t *widget, rtgui_point_t *point);
-    /* get the logic position of a physical rect on widget */
-    void rtgui_widget_rect_to_logic(rtgui_widget_t *widget, rtgui_rect_t *rect);
+/* get the logic position of a physical point on widget */
+void rtgui_widget_point_to_logic(rtgui_widget_t *widget, rtgui_point_t *point);
+/* get the logic position of a physical rect on widget */
+void rtgui_widget_rect_to_logic(rtgui_widget_t *widget, rtgui_rect_t *rect);
 
-    /* move widget and its children to a logic point */
-    void rtgui_widget_move_to_logic(rtgui_widget_t *widget, int dx, int dy);
+/* move widget and its children to a logic point */
+void rtgui_widget_move_to_logic(rtgui_widget_t *widget, int dx, int dy);
 
-    /* update the clip info of widget */
-    void rtgui_widget_update_clip(rtgui_widget_t *widget);
+/* update the clip info of widget */
+void rtgui_widget_update_clip(rtgui_widget_t *widget);
 
-    /* get the toplevel widget of widget */
-    struct rtgui_win *rtgui_widget_get_toplevel(rtgui_widget_t *widget);
-    rt_bool_t rtgui_widget_onupdate_toplvl(struct rtgui_object *object, struct rtgui_event *event);
+/* get the toplevel widget of widget */
+struct rtgui_win *rtgui_widget_get_toplevel(rtgui_widget_t *widget);
+rt_bool_t rtgui_widget_onupdate_toplvl(struct rtgui_object *object, struct rtgui_event *event);
 
-    void rtgui_widget_show(rtgui_widget_t *widget);
-    rt_bool_t rtgui_widget_onshow(struct rtgui_object *object, struct rtgui_event *event);
-    void rtgui_widget_hide(rtgui_widget_t *widget);
-    rt_bool_t rtgui_widget_onhide(struct rtgui_object *object, struct rtgui_event *event);
-    void rtgui_widget_update(rtgui_widget_t *widget);
+void rtgui_widget_show(rtgui_widget_t *widget);
+rt_bool_t rtgui_widget_onshow(struct rtgui_object *object, struct rtgui_event *event);
+void rtgui_widget_hide(rtgui_widget_t *widget);
+rt_bool_t rtgui_widget_onhide(struct rtgui_object *object, struct rtgui_event *event);
+void rtgui_widget_update(rtgui_widget_t *widget);
 
-    /* get parent color */
-    rtgui_color_t rtgui_widget_get_parent_foreground(rtgui_widget_t *widget);
-    rtgui_color_t rtgui_widget_get_parent_background(rtgui_widget_t *widget);
+/* get parent color */
+rtgui_color_t rtgui_widget_get_parent_foreground(rtgui_widget_t *widget);
+rtgui_color_t rtgui_widget_get_parent_background(rtgui_widget_t *widget);
 
-    /* get the next sibling of widget */
-    rtgui_widget_t *rtgui_widget_get_next_sibling(rtgui_widget_t *widget);
-    /* get the prev sibling of widget */
-    rtgui_widget_t *rtgui_widget_get_prev_sibling(rtgui_widget_t *widget);
+/* get the next sibling of widget */
+rtgui_widget_t *rtgui_widget_get_next_sibling(rtgui_widget_t *widget);
+/* get the prev sibling of widget */
+rtgui_widget_t *rtgui_widget_get_prev_sibling(rtgui_widget_t *widget);
 
-    /* dump widget information */
-    void rtgui_widget_dump(rtgui_widget_t *widget);
+/* dump widget information */
+void rtgui_widget_dump(rtgui_widget_t *widget);
 
 #ifdef __cplusplus
 }

+ 1 - 1
components/rtgui/include/rtgui/widgets/window.h

@@ -130,7 +130,7 @@ void rtgui_win_destroy(rtgui_win_t *win);
 rt_bool_t rtgui_win_close(struct rtgui_win *win);
 
 rt_base_t rtgui_win_show(struct rtgui_win *win, rt_bool_t is_modal);
-void rtgui_win_hiden(rtgui_win_t *win);
+void rtgui_win_hide(rtgui_win_t *win);
 void rtgui_win_end_modal(rtgui_win_t *win, rtgui_modal_code_t modal_code);
 rt_err_t rtgui_win_activate(struct rtgui_win *win);
 rt_bool_t rtgui_win_is_activated(struct rtgui_win *win);

+ 37 - 0
components/rtgui/server/driver.c

@@ -41,6 +41,7 @@ rt_err_t rtgui_graphic_set_device(rt_device_t device)
 {
     rt_err_t result;
     struct rt_device_graphic_info info;
+	struct rtgui_graphic_ext_ops *ext_ops;
 
     /* get framebuffer address */
     result = rt_device_control(device, RTGRAPHIC_CTRL_GET_INFO, &info);
@@ -59,6 +60,13 @@ rt_err_t rtgui_graphic_set_device(rt_device_t device)
     _driver.pitch = _driver.width * _driver.bits_per_pixel / 8;
     _driver.framebuffer = info.framebuffer;
 
+	/* get graphic extension operations */
+	result = rt_device_control(device, RTGRAPHIC_CTRL_GET_EXT, &ext_ops);
+	if (result == RT_EOK)
+	{
+		_driver.ext_ops = ext_ops;
+	}
+
     if (info.framebuffer != RT_NULL)
     {
         /* is a frame buffer device */
@@ -70,6 +78,11 @@ rt_err_t rtgui_graphic_set_device(rt_device_t device)
         _driver.ops = rtgui_pixel_device_get_ops(_driver.pixel_format);
     }
 
+#ifdef RTGUI_USING_HW_CURSOR
+	/* set default cursor image */
+	rtgui_cursor_set_image(RTGUI_CURSOR_ARROW);
+#endif
+
     return RT_EOK;
 }
 RTM_EXPORT(rtgui_graphic_set_device);
@@ -100,3 +113,27 @@ rt_uint8_t *rtgui_graphic_driver_get_default_framebuffer(void)
 }
 RTM_EXPORT(rtgui_graphic_driver_get_default_framebuffer);
 
+#ifdef RTGUI_USING_HW_CURSOR
+void rtgui_cursor_set_position(rt_uint16_t x, rt_uint16_t y)
+{
+	rt_uint32_t value;
+
+	if (_driver.device != RT_NULL)
+	{
+		value = (x << 16 | y);
+		rt_device_control(_driver.device, RT_DEVICE_CTRL_CURSOR_SET_POSITION, &value);
+	}
+}
+
+void rtgui_cursor_set_image(enum rtgui_cursor_type type)
+{
+	rt_uint32_t value;
+
+	if (_driver.device != RT_NULL)
+	{
+		value = type;
+		rt_device_control(_driver.device, RT_DEVICE_CTRL_CURSOR_SET_TYPE, &value);
+	}
+};
+#endif
+

+ 15 - 0
components/rtgui/server/mouse.c

@@ -255,6 +255,10 @@ void rtgui_mouse_moveto(int x, int y)
             rtgui_mouse_show_cursor();
 #endif
         }
+
+#ifdef RTGUI_USING_HW_CURSOR
+		rtgui_cursor_set_position(_rtgui_cursor->cx, _rtgui_cursor->cy);
+#endif
     }
 
 #ifdef RTGUI_USING_MOUSE_CURSOR
@@ -262,6 +266,17 @@ void rtgui_mouse_moveto(int x, int y)
 #endif
 }
 
+void rtgui_mouse_set_position(int x, int y)
+{
+	/* move current cursor */
+	_rtgui_cursor->cx = x;
+	_rtgui_cursor->cy = y;
+
+#ifdef RTGUI_USING_HW_CURSOR
+	rtgui_cursor_set_position(_rtgui_cursor->cx, _rtgui_cursor->cy);
+#endif
+}
+
 #ifdef RTGUI_USING_MOUSE_CURSOR
 void rtgui_mouse_set_cursor_enable(rt_bool_t enable)
 {

+ 2 - 0
components/rtgui/server/mouse.h

@@ -31,6 +31,8 @@ typedef struct rtgui_mouse_monitor rtgui_mouse_monitor_t;
 void rtgui_mouse_init(void);
 void rtgui_mouse_fini(void);
 void rtgui_mouse_moveto(int x, int y);
+/* set cursor position */
+void rtgui_mouse_set_position(int x, int y); 
 
 void rtgui_mouse_set_cursor_enable(rt_bool_t enable);
 void rtgui_mouse_set_cursor(rtgui_image_t *cursor);

+ 42 - 31
components/rtgui/server/server.c

@@ -22,9 +22,7 @@
 #include "mouse.h"
 #include "topwin.h"
 
-static struct rt_thread *rtgui_server_tid;
-
-static struct rtgui_app *rtgui_server_application = RT_NULL;
+static struct rtgui_app *rtgui_server_app = RT_NULL;
 static struct rtgui_app *rtgui_wm_application = RT_NULL;
 
 void rtgui_server_handle_update(struct rtgui_event_update_end *event)
@@ -57,6 +55,9 @@ void rtgui_server_handle_mouse_btn(struct rtgui_event_mouse *event)
     /* re-init to server thread */
     RTGUI_EVENT_MOUSE_BUTTON_INIT(event);
 
+	/* set cursor position */
+	rtgui_mouse_set_position(event->x, event->y);
+
 #ifdef RTGUI_USING_WINMOVE
     if (rtgui_winrect_is_moved() &&
             event->button & (RTGUI_MOUSE_BUTTON_LEFT | RTGUI_MOUSE_BUTTON_UP))
@@ -87,7 +88,7 @@ void rtgui_server_handle_mouse_btn(struct rtgui_event_mouse *event)
             }
 
             /* send to client thread */
-            rtgui_send(topwin->tid, &(ewin.parent), sizeof(ewin));
+            rtgui_send(topwin->app, &(ewin.parent), sizeof(ewin));
 
             return;
         }
@@ -100,9 +101,10 @@ void rtgui_server_handle_mouse_btn(struct rtgui_event_mouse *event)
     {
         event->wid = wnd->wid;
 
-        if (rtgui_topwin_get_focus() != wnd)
+        /* only raise window if the button is pressed down */
+        if (event->button & RTGUI_MOUSE_BUTTON_DOWN
+            && rtgui_topwin_get_focus() != wnd)
         {
-            /* raise this window */
             rtgui_topwin_activate_topwin(wnd);
         }
 
@@ -114,7 +116,7 @@ void rtgui_server_handle_mouse_btn(struct rtgui_event_mouse *event)
         else
         {
             /* send mouse event to thread */
-            rtgui_send(wnd->tid, (struct rtgui_event *)event, sizeof(struct rtgui_event_mouse));
+            rtgui_send(wnd->app, (struct rtgui_event *)event, sizeof(struct rtgui_event_mouse));
         }
         return ;
     }
@@ -146,7 +148,7 @@ void rtgui_server_handle_mouse_motion(struct rtgui_event_mouse *event)
     {
         event->wid = last_monitor_topwin->wid;
         /* send mouse motion event */
-        rtgui_send(last_monitor_topwin->tid, &(event->parent), sizeof(struct rtgui_event_mouse));
+        rtgui_send(last_monitor_topwin->app, &(event->parent), sizeof(struct rtgui_event_mouse));
     }
 
     if (last_monitor_topwin != win)
@@ -157,7 +159,7 @@ void rtgui_server_handle_mouse_motion(struct rtgui_event_mouse *event)
             event->wid = last_monitor_topwin->wid;
 
             /* send mouse motion event */
-            rtgui_send(last_monitor_topwin->tid, &(event->parent), sizeof(struct rtgui_event_mouse));
+            rtgui_send(last_monitor_topwin->app, &(event->parent), sizeof(struct rtgui_event_mouse));
         }
     }
 
@@ -183,7 +185,7 @@ void rtgui_server_handle_kbd(struct rtgui_event_kbd *event)
         event->wid = wnd->wid;
 
         /* send keyboard event to thread */
-        rtgui_send(wnd->tid, (struct rtgui_event *)event, sizeof(struct rtgui_event_kbd));
+        rtgui_send(wnd->app, (struct rtgui_event *)event, sizeof(struct rtgui_event_kbd));
 
         return;
     }
@@ -207,7 +209,7 @@ static rt_bool_t rtgui_server_event_handler(struct rtgui_object *object,
         if (rtgui_wm_application != RT_NULL)
         {
             /* forward event to wm application */
-            rtgui_send(rtgui_wm_application->tid, event, sizeof(struct rtgui_event_application));
+            rtgui_send(rtgui_wm_application, event, sizeof(struct rtgui_event_application));
         }
         else
         {
@@ -349,12 +351,12 @@ static void rtgui_server_entry(void *parameter)
 #endif
 
     /* create rtgui server application */
-    rtgui_server_application = rtgui_app_create(rtgui_server_tid,
-                               "rtgui");
-    if (rtgui_server_application == RT_NULL)
+    rtgui_server_app = rtgui_app_create("rtgui");
+    rt_kprintf("RTGUI: create server: %p", rtgui_server_app);
+    if (rtgui_server_app == RT_NULL)
         return;
 
-    rtgui_object_set_event_handler(RTGUI_OBJECT(rtgui_server_application),
+    rtgui_object_set_event_handler(RTGUI_OBJECT(rtgui_server_app),
                                    rtgui_server_event_handler);
     /* init mouse and show */
     rtgui_mouse_init();
@@ -362,24 +364,24 @@ static void rtgui_server_entry(void *parameter)
     rtgui_mouse_show_cursor();
 #endif
 
-    rtgui_app_run(rtgui_server_application);
+    rtgui_app_run(rtgui_server_app);
 
-    rtgui_app_destroy(rtgui_server_application);
-    rtgui_server_application = RT_NULL;
+    rtgui_app_destroy(rtgui_server_app);
+    rtgui_server_app = RT_NULL;
 }
 
 void rtgui_server_post_event(struct rtgui_event *event, rt_size_t size)
 {
-    if (rtgui_server_tid != RT_NULL)
-        rtgui_send(rtgui_server_tid, event, size);
+    if (rtgui_server_app != RT_NULL)
+        rtgui_send(rtgui_server_app, event, size);
     else
         rt_kprintf("post when server is not running\n");
 }
 
 rt_err_t rtgui_server_post_event_sync(struct rtgui_event *event, rt_size_t size)
 {
-    if (rtgui_server_tid != RT_NULL)
-        return rtgui_send_sync(rtgui_server_tid, event, size);
+    if (rtgui_server_app != RT_NULL)
+        return rtgui_send_sync(rtgui_server_app, event, size);
     else
     {
         rt_kprintf("post when server is not running\n");
@@ -387,18 +389,27 @@ rt_err_t rtgui_server_post_event_sync(struct rtgui_event *event, rt_size_t size)
     }
 }
 
+struct rtgui_app* rtgui_get_server(void)
+{
+    rt_thread_t tid = rt_thread_find("rtgui");
+
+    if (tid == RT_NULL)
+        return RT_NULL;
+    return (struct rtgui_app*)tid->user_data;
+}
+RTM_EXPORT(rtgui_get_server);
+
 void rtgui_server_init(void)
 {
-    if (rtgui_server_tid != RT_NULL)
-        return;
+    rt_thread_t tid;
 
-    rtgui_server_tid = rt_thread_create("rtgui",
-                                        rtgui_server_entry, RT_NULL,
-                                        RTGUI_SVR_THREAD_STACK_SIZE,
-                                        RTGUI_SVR_THREAD_PRIORITY,
-                                        RTGUI_SVR_THREAD_TIMESLICE);
+    tid = rt_thread_create("rtgui",
+                           rtgui_server_entry, RT_NULL,
+                           RTGUI_SVR_THREAD_STACK_SIZE,
+                           RTGUI_SVR_THREAD_PRIORITY,
+                           RTGUI_SVR_THREAD_TIMESLICE);
 
     /* start rtgui server thread */
-    if (rtgui_server_tid != RT_NULL)
-        rt_thread_startup(rtgui_server_tid);
+    if (tid != RT_NULL)
+        rt_thread_startup(tid);
 }

+ 10 - 10
components/rtgui/server/topwin.c

@@ -102,7 +102,7 @@ rt_err_t rtgui_topwin_add(struct rtgui_event_win_create *event)
 #else
     topwin->extent = event->extent;
 #endif
-    topwin->tid    = event->parent.sender;
+    topwin->app    = event->parent.sender;
 
     if (event->parent_window == RT_NULL)
     {
@@ -337,7 +337,7 @@ static void _rtgui_topwin_only_activate(struct rtgui_topwin *topwin)
     topwin->flag |= WINTITLE_ACTIVATE;
 
     event.wid = topwin->wid;
-    rtgui_send(topwin->tid, &(event.parent), sizeof(struct rtgui_event_win));
+    rtgui_send(topwin->app, &(event.parent), sizeof(struct rtgui_event_win));
 
     /* redraw title */
     if (topwin->title != RT_NULL)
@@ -366,11 +366,11 @@ static void _rtgui_topwin_deactivate(struct rtgui_topwin *topwin)
     struct rtgui_event_win event;
 
     RT_ASSERT(topwin != RT_NULL);
-    RT_ASSERT(topwin->tid != RT_NULL);
+    RT_ASSERT(topwin->app != RT_NULL);
 
     RTGUI_EVENT_WIN_DEACTIVATE_INIT(&event);
     event.wid = topwin->wid;
-    rtgui_send(topwin->tid,
+    rtgui_send(topwin->app,
                &event.parent, sizeof(struct rtgui_event_win));
 
     topwin->flag &= ~WINTITLE_ACTIVATE;
@@ -495,7 +495,7 @@ static void _rtgui_topwin_draw_tree(struct rtgui_topwin *topwin, struct rtgui_ev
     }
 
     epaint->wid = topwin->wid;
-    rtgui_send(topwin->tid, &(epaint->parent), sizeof(struct rtgui_event_paint));
+    rtgui_send(topwin->app, &(epaint->parent), sizeof(struct rtgui_event_paint));
 
     rtgui_dlist_foreach(node, &topwin->child_list, prev)
     {
@@ -748,7 +748,7 @@ rt_err_t rtgui_topwin_move(struct rtgui_event_win_move *event)
         struct rtgui_event_paint epaint;
         RTGUI_EVENT_PAINT_INIT(&epaint);
         epaint.wid = topwin->wid;
-        rtgui_send(topwin->tid, &(epaint.parent), sizeof(epaint));
+        rtgui_send(topwin->app, &(epaint.parent), sizeof(epaint));
     }
 
     return RT_EOK;
@@ -945,7 +945,7 @@ static void rtgui_topwin_update_clip(void)
 
         /* send clip event to destination window */
         eclip.wid = top->wid;
-        rtgui_send(top->tid, &(eclip.parent), sizeof(struct rtgui_event_clip_info));
+        rtgui_send(top->app, &(eclip.parent), sizeof(struct rtgui_event_clip_info));
 
         /* move to next sibling tree */
         if (top->parent == RT_NULL)
@@ -991,7 +991,7 @@ static void _rtgui_topwin_redraw_tree(struct rtgui_dlist_node *list,
         if (rtgui_rect_is_intersect(rect, &(topwin->extent)) == RT_EOK)
         {
             epaint->wid = topwin->wid;
-            rtgui_send(topwin->tid, &(epaint->parent), sizeof(*epaint));
+            rtgui_send(topwin->app, &(epaint->parent), sizeof(*epaint));
 
             /* draw title */
             if (topwin->title != RT_NULL)
@@ -1059,7 +1059,7 @@ void rtgui_topwin_title_onmouse(struct rtgui_topwin *win, struct rtgui_event_mou
     if (rtgui_rect_contains_point(&win->extent, event->x, event->y) == RT_EOK)
     {
         /* send mouse event to thread */
-        rtgui_send(win->tid, &(event->parent), sizeof(struct rtgui_event_mouse));
+        rtgui_send(win->app, &(event->parent), sizeof(struct rtgui_event_mouse));
         return;
     }
 
@@ -1098,7 +1098,7 @@ void rtgui_topwin_title_onmouse(struct rtgui_topwin *win, struct rtgui_event_mou
                 /* send close event to window */
                 RTGUI_EVENT_WIN_CLOSE_INIT(&event);
                 event.wid = win->wid;
-                rtgui_send(win->tid, &(event.parent), sizeof(struct rtgui_event_win));
+                rtgui_send(win->app, &(event.parent), sizeof(struct rtgui_event_win));
             }
         }
     }

+ 49 - 0
components/rtgui/utils/perfect_hash/README

@@ -0,0 +1,49 @@
+
+perfect_hash.py
+
+Ilan Schnell <ilanschnell@gmail.com>, 2008
+
+
+Generate a minimal perfect hash function for the keys in a file,
+desired hash values may be specified within this file as well.
+A given code template is filled with parameters, such that the
+output is code which implements the hash function.
+Templates can easily be constructed for any programming language.
+
+The code is based on an a program A.M. Kuchling wrote:
+http://www.amk.ca/python/code/perfect-hash
+
+The algorithm the program uses is described in the paper
+'Optimal algorithms for minimal perfect hashing',
+Z. J. Czech, G. Havas and B.S. Majewski.
+http://citeseer.ist.psu.edu/122364.html
+
+
+Content:
+
+perfect_hash.py     The actual program, try $ ./perfect_hash.py animals.txt
+
+doc                 HTML and plain text documentation
+
+example1-C          An example which shows how to generate a C program
+                    which implements a perfect hash table.
+
+example2-C          Another example in C.
+
+example-C++         In this C++ example, a class is used to define the
+                    interface to a static lookup table.
+
+example-PyModule    A lookup table in implemented as a C extension module
+                    for Python.
+
+example-Python      Some small Python programs which show how to access
+                    some functions and classes in perfect_hash.py directly,
+                    i.e. using perfect_hash has a Python module, rather
+                    than a standalone program.
+
+graph               A small program `py2dot' which converts the default python
+                    output code from perfect_hash.py into a .dot-file which
+                    can be used by Graphviz (see http://www.graphviz.org/) to
+                    create a picture of the graph.
+
+run                 Runs some tests.

+ 0 - 0
components/rtgui/utils/perfect_hash/__init__.py


+ 7 - 0
components/rtgui/utils/perfect_hash/animals.txt

@@ -0,0 +1,7 @@
+# 'animals.txt'
+Elephant
+Horse
+Camel
+Python
+Dog
+Cat

+ 22 - 0
components/rtgui/utils/perfect_hash/doc/Makefile

@@ -0,0 +1,22 @@
+
+
+all: doc.html doc.txt
+
+
+doc.html: doc.in parameters.txt mktable.py
+	./mktable.py >table.html
+	markdown doc.in | \
+            sed -e "s,<h6>table</h6>,m4_include(\`table.html')," | \
+            m4 -P >doc.html
+	rm table.html
+
+
+doc.txt: doc.in parameters.txt
+	sed <doc.in -e "s,###### table,m4_include(\`parameters.txt')," \
+                    -e "s,\`\([^\`]*\)\`,'\1',g" | m4 -P >doc.txt
+
+
+clean:
+	rm doc.html doc.txt
+
+

BIN
components/rtgui/utils/perfect_hash/doc/czech92optimal.pdf


+ 136 - 0
components/rtgui/utils/perfect_hash/doc/doc.html

@@ -0,0 +1,136 @@
+
+
+<h2>Generic Perfect Hash Generator</h2>
+<p><em>Ilan Schnell, 2008</em>
+</p>
+<p>perfect_hash.py provides a perfect hash generator which is not language
+   specific.  That is, the generator can output a perfect hash function for
+   a given set of keys in any programming language, this is achieved by
+   filling a given code template.
+</p>
+
+<h3>Acknowledgments:</h3>
+<p>This code is derived from A. M. Kuchling's 
+   <a href="http://www.amk.ca/python/code/perfect-hash">Perfect Minimal Hash Generator</a>.
+</p>
+
+<h3>Introduction:</h3>
+<p>A perfect hash function of a certain set S of keys is a hash function
+   which maps all keys in S to different numbers.
+   That means that for the set S,
+   the hash function is collision-free, or perfect.
+   Further, a perfect hash function is called minimal when it maps n keys
+   to n <em>consecutive</em> integers, usually in the range from 0 to n-1.
+</p>
+<p>After coming across A. M. Kuchling's Perfect Minimal Hash Generator,
+   I decided to write a general tool for generating perfect hashes.
+   It is general in the sense that it can produce perfect hash functions
+   for almost any programming language.
+   A given code template is filled with parameters,
+   such that the output is code which implements the hash function.
+</p>
+<p>The algorithm the program uses is described in the paper
+   <a href="http://citeseer.ist.psu.edu/122364.html">&quot;Optimal algorithms for minimal perfect hashing&quot;</a>,
+   Z. J. Czech, G. Havas and B.S. Majewski.
+</p>
+<p>I tried to illustrate the algorithm and explain how it works on
+   <a href="http://ilan.schnell-web.net/prog/perfect-hash/algo.html">this page</a>.
+</p>
+
+<h3>Usage:</h3>
+<p>Given a set of keys which are ordinary character string,
+   the program returns a minimal perfect hash function.
+   This hash function is returned in the form of Python code by default.
+   Suppose we have a file with keys:
+</p>
+<pre><code># 'animals.txt'
+Elephant
+Horse
+Camel
+Python
+Dog
+Cat
+</code></pre><p>The exact way this file is parsed can be specified using command line
+   options, for example it is possible to only read one column from a file
+   which contains different items in each row.
+   The program is invoked like this:
+</p>
+<pre><code># =======================================================================
+# ================= Python code for perfect hash function ===============
+# =======================================================================
+
+G = [0, 0, 4, 1, 0, 3, 8, 1, 6]
+
+S1 = [5, 0, 0, 6, 1, 0, 4, 7]
+S2 = [7, 3, 6, 7, 8, 5, 7, 6]
+
+def hash_f(key, T):
+    return sum(T[i % 8] * ord(c) for i, c in enumerate(str(key))) % 9
+
+def perfect_hash(key):
+    return (G[hash_f(key, S1)] + G[hash_f(key, S2)]) % 9
+
+# ============================ Sanity check =============================
+
+K = [&quot;Elephant&quot;, &quot;Horse&quot;, &quot;Camel&quot;, &quot;Python&quot;, &quot;Dog&quot;, &quot;Cat&quot;]
+H = [0, 1, 2, 3, 4, 5]
+
+assert len(K) == len(H) == 6
+
+for k, h in zip(K, H):
+    assert perfect_hash(k) == h
+</code></pre><p>The way the program works is by filling a code template with the calculated
+   parameters.  The program can take such a template in form of a file and
+   fill in the calculated parameters, this allows the generation of perfect
+   hash function in any programming language.  The hash function is kept quite
+   simple and does not require machine or language specific byte level operations
+   which might be hard to implement in the target language.
+   The following parameters are available in the template, and will expand to:
+</p>
+<table>
+  <tr><th>string</th><th>expands to</th></tr>
+  <tr><td><code>$NS</code></td><td>the length of S1 and S2</td></tr>
+  <tr><td><code>$S1</code></td><td>array of integers S1</td></tr>
+  <tr><td><code>$S2</code></td><td>array of integers S2</td></tr>
+  <tr><td><code>$NG</code></td><td>length of array G</td></tr>
+  <tr><td><code>$G</code></td><td>array of integers G</td></tr>
+  <tr><td><code>$NK</code></td><td>the number of keys, i.e. length of array K and H</td></tr>
+  <tr><td><code>$K</code></td><td>array with the quoted keys</td></tr>
+  <tr><td><code>$H</code></td><td>array of integer hash values</td></tr>
+  <tr><td><code>$$</code></td><td><code>$</code> (a literal dollar sign)</td></tr>
+</table>
+<p>A literal <code>$</code> is escaped as <code>$$</code>.  Since the syntax for arrays is not the
+   same in all programming languages, some specifics can be adjusted using
+   command line options.
+   The section of the built-in template which creates the actual hash function
+   is:
+</p>
+<pre><code>G = [$G]
+
+S1 = [$S1]
+S2 = [$S2]
+
+def hash_f(key, T):
+    return sum(T[i % $NS] * ord(c) for i, c in enumerate(str(key))) % $NG
+
+def perfect_hash(key):
+    return (G[hash_f(key, S1)] + G[hash_f(key, S2)]) % $NG
+</code></pre><p>Using code templates, makes this program very flexible.  The package comes
+   with several complete examples for C and C++.  There are many choices one
+   faces when implementing a static hash table: do the parameter lists go into
+   a separate header file, should the API for the table only contain the hash
+   values, but not the objects being mapped, and so on.
+   All these various choices are possible because of the template is simply
+   filled with the parameters, no matter what else is inside the template.
+</p>
+<p>Another possible use the program is as a python module.  The functions and
+   classes in <code>perfect_hash.py</code> are documented and have clean interfaces.
+   The folder <code>example-Python</code> has examples which shows how the module
+   can be used directly in this way.
+</p>
+
+<h3>Requirement:</h3>
+<p>Python 2.5
+</p>
+
+

+ 130 - 0
components/rtgui/utils/perfect_hash/doc/doc.in

@@ -0,0 +1,130 @@
+
+Generic Perfect Hash Generator
+------------------------------
+
+*Ilan Schnell, 2008*
+
+perfect_hash.py provides a perfect hash generator which is not language
+specific.  That is, the generator can output a perfect hash function for
+a given set of keys in any programming language, this is achieved by
+filling a given code template.
+
+### Acknowledgments:
+
+This code is derived from A. M. Kuchling's 
+[Perfect Minimal Hash Generator](http://www.amk.ca/python/code/perfect-hash).
+
+### Introduction:
+
+A perfect hash function of a certain set S of keys is a hash function
+which maps all keys in S to different numbers.
+That means that for the set S,
+the hash function is collision-free, or perfect.
+Further, a perfect hash function is called minimal when it maps n keys
+to n *consecutive* integers, usually in the range from 0 to n-1.
+
+After coming across A. M. Kuchling's Perfect Minimal Hash Generator,
+I decided to write a general tool for generating perfect hashes.
+It is general in the sense that it can produce perfect hash functions
+for almost any programming language.
+A given code template is filled with parameters,
+such that the output is code which implements the hash function.
+
+The algorithm the program uses is described in the paper
+["Optimal algorithms for minimal perfect hashing"]
+(http://citeseer.ist.psu.edu/122364.html),
+Z. J. Czech, G. Havas and B.S. Majewski.
+
+I tried to illustrate the algorithm and explain how it works on
+[this page](http://ilan.schnell-web.net/prog/perfect-hash/algo.html).
+
+### Usage:
+
+Given a set of keys which are ordinary character string,
+the program returns a minimal perfect hash function.
+This hash function is returned in the form of Python code by default.
+Suppose we have a file with keys:
+
+    # 'animals.txt'
+    Elephant
+    Horse
+    Camel
+    Python
+    Dog
+    Cat
+
+
+The exact way this file is parsed can be specified using command line
+options, for example it is possible to only read one column from a file
+which contains different items in each row.
+The program is invoked like this:
+
+    # =======================================================================
+    # ================= Python code for perfect hash function ===============
+    # =======================================================================
+    
+    G = [0, 0, 4, 1, 0, 3, 8, 1, 6]
+    
+    S1 = [5, 0, 0, 6, 1, 0, 4, 7]
+    S2 = [7, 3, 6, 7, 8, 5, 7, 6]
+    
+    def hash_f(key, T):
+        return sum(T[i % 8] * ord(c) for i, c in enumerate(str(key))) % 9
+    
+    def perfect_hash(key):
+        return (G[hash_f(key, S1)] + G[hash_f(key, S2)]) % 9
+    
+    # ============================ Sanity check =============================
+    
+    K = ["Elephant", "Horse", "Camel", "Python", "Dog", "Cat"]
+    H = [0, 1, 2, 3, 4, 5]
+    
+    assert len(K) == len(H) == 6
+    
+    for k, h in zip(K, H):
+        assert perfect_hash(k) == h
+
+
+The way the program works is by filling a code template with the calculated
+parameters.  The program can take such a template in form of a file and
+fill in the calculated parameters, this allows the generation of perfect
+hash function in any programming language.  The hash function is kept quite
+simple and does not require machine or language specific byte level operations
+which might be hard to implement in the target language.
+The following parameters are available in the template, and will expand to:
+
+###### table
+
+A literal `$` is escaped as `$$`.  Since the syntax for arrays is not the
+same in all programming languages, some specifics can be adjusted using
+command line options.
+The section of the built-in template which creates the actual hash function
+is:
+
+    G = [$G]
+    
+    S1 = [$S1]
+    S2 = [$S2]
+    
+    def hash_f(key, T):
+        return sum(T[i % $NS] * ord(c) for i, c in enumerate(str(key))) % $NG
+    
+    def perfect_hash(key):
+        return (G[hash_f(key, S1)] + G[hash_f(key, S2)]) % $NG
+
+Using code templates, makes this program very flexible.  The package comes
+with several complete examples for C and C++.  There are many choices one
+faces when implementing a static hash table: do the parameter lists go into
+a separate header file, should the API for the table only contain the hash
+values, but not the objects being mapped, and so on.
+All these various choices are possible because of the template is simply
+filled with the parameters, no matter what else is inside the template.
+
+Another possible use the program is as a python module.  The functions and
+classes in `perfect_hash.py` are documented and have clean interfaces.
+The folder `example-Python` has examples which shows how the module
+can be used directly in this way.
+
+### Requirement:
+
+Python 2.5

+ 141 - 0
components/rtgui/utils/perfect_hash/doc/doc.txt

@@ -0,0 +1,141 @@
+
+Generic Perfect Hash Generator
+------------------------------
+
+*Ilan Schnell, 2008*
+
+perfect_hash.py provides a perfect hash generator which is not language
+specific.  That is, the generator can output a perfect hash function for
+a given set of keys in any programming language, this is achieved by
+filling a given code template.
+
+### Acknowledgments:
+
+This code is derived from A. M. Kuchling's 
+[Perfect Minimal Hash Generator](http://www.amk.ca/python/code/perfect-hash).
+
+### Introduction:
+
+A perfect hash function of a certain set S of keys is a hash function
+which maps all keys in S to different numbers.
+That means that for the set S,
+the hash function is collision-free, or perfect.
+Further, a perfect hash function is called minimal when it maps n keys
+to n *consecutive* integers, usually in the range from 0 to n-1.
+
+After coming across A. M. Kuchling's Perfect Minimal Hash Generator,
+I decided to write a general tool for generating perfect hashes.
+It is general in the sense that it can produce perfect hash functions
+for almost any programming language.
+A given code template is filled with parameters,
+such that the output is code which implements the hash function.
+
+The algorithm the program uses is described in the paper
+["Optimal algorithms for minimal perfect hashing"]
+(http://citeseer.ist.psu.edu/122364.html),
+Z. J. Czech, G. Havas and B.S. Majewski.
+
+I tried to illustrate the algorithm and explain how it works on
+[this page](http://ilan.schnell-web.net/prog/perfect-hash/algo.html).
+
+### Usage:
+
+Given a set of keys which are ordinary character string,
+the program returns a minimal perfect hash function.
+This hash function is returned in the form of Python code by default.
+Suppose we have a file with keys:
+
+    # 'animals.txt'
+    Elephant
+    Horse
+    Camel
+    Python
+    Dog
+    Cat
+
+
+The exact way this file is parsed can be specified using command line
+options, for example it is possible to only read one column from a file
+which contains different items in each row.
+The program is invoked like this:
+
+    # =======================================================================
+    # ================= Python code for perfect hash function ===============
+    # =======================================================================
+    
+    G = [0, 0, 4, 1, 0, 3, 8, 1, 6]
+    
+    S1 = [5, 0, 0, 6, 1, 0, 4, 7]
+    S2 = [7, 3, 6, 7, 8, 5, 7, 6]
+    
+    def hash_f(key, T):
+        return sum(T[i % 8] * ord(c) for i, c in enumerate(str(key))) % 9
+    
+    def perfect_hash(key):
+        return (G[hash_f(key, S1)] + G[hash_f(key, S2)]) % 9
+    
+    # ============================ Sanity check =============================
+    
+    K = ["Elephant", "Horse", "Camel", "Python", "Dog", "Cat"]
+    H = [0, 1, 2, 3, 4, 5]
+    
+    assert len(K) == len(H) == 6
+    
+    for k, h in zip(K, H):
+        assert perfect_hash(k) == h
+
+
+The way the program works is by filling a code template with the calculated
+parameters.  The program can take such a template in form of a file and
+fill in the calculated parameters, this allows the generation of perfect
+hash function in any programming language.  The hash function is kept quite
+simple and does not require machine or language specific byte level operations
+which might be hard to implement in the target language.
+The following parameters are available in the template, and will expand to:
+
+    string  |  expands to
+    --------+--------------------------------
+      $NS   |  the length of S1 and S2
+      $S1   |  array of integers S1
+      $S2   |  array of integers S2
+      $NG   |  length of array G
+      $G    |  array of integers G
+      $NK   |  the number of keys, i.e. length of array K and H
+      $K    |  array with the quoted keys
+      $H    |  array of integer hash values
+      $$    |  $ (a literal dollar sign)
+
+
+A literal '$' is escaped as '$$'.  Since the syntax for arrays is not the
+same in all programming languages, some specifics can be adjusted using
+command line options.
+The section of the built-in template which creates the actual hash function
+is:
+
+    G = [$G]
+    
+    S1 = [$S1]
+    S2 = [$S2]
+    
+    def hash_f(key, T):
+        return sum(T[i % $NS] * ord(c) for i, c in enumerate(str(key))) % $NG
+    
+    def perfect_hash(key):
+        return (G[hash_f(key, S1)] + G[hash_f(key, S2)]) % $NG
+
+Using code templates, makes this program very flexible.  The package comes
+with several complete examples for C and C++.  There are many choices one
+faces when implementing a static hash table: do the parameter lists go into
+a separate header file, should the API for the table only contain the hash
+values, but not the objects being mapped, and so on.
+All these various choices are possible because of the template is simply
+filled with the parameters, no matter what else is inside the template.
+
+Another possible use the program is as a python module.  The functions and
+classes in 'perfect_hash.py' are documented and have clean interfaces.
+The folder 'example-Python' has examples which shows how the module
+can be used directly in this way.
+
+### Requirement:
+
+Python 2.5

+ 22 - 0
components/rtgui/utils/perfect_hash/doc/mktable.py

@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+import re
+
+def convert(line, head = False):
+    pat = re.compile(r'([$]\S*)')
+    line = pat.sub(r'<code>\1</code>', line)
+    
+    row = [x.strip() for x in line.split('|')]
+    fmt = '  <tr><td>%s</td><td>%s</td></tr>'
+    if head:
+        fmt = fmt.replace('td', 'th')
+    print fmt % tuple(row)
+
+
+f = file('parameters.txt')
+
+print '<table>'
+convert(f.readline(), head = True)
+f.readline()
+for line in f:
+    convert(line)
+print '</table>'

+ 11 - 0
components/rtgui/utils/perfect_hash/doc/parameters.txt

@@ -0,0 +1,11 @@
+    string  |  expands to
+    --------+--------------------------------
+      $NS   |  the length of S1 and S2
+      $S1   |  array of integers S1
+      $S2   |  array of integers S2
+      $NG   |  length of array G
+      $G    |  array of integers G
+      $NK   |  the number of keys, i.e. length of array K and H
+      $K    |  array with the quoted keys
+      $H    |  array of integer hash values
+      $$    |  $ (a literal dollar sign)

+ 31 - 0
components/rtgui/utils/perfect_hash/example-C++/Makefile

@@ -0,0 +1,31 @@
+
+CXX = g++ -Wall
+
+
+lookup: main.o states-code.o
+	$(CXX) -o $@ $^
+
+
+main.o: main.cc states-code.hh
+	$(CXX) -c $<
+
+
+states-code.o: states-code.cc states-code.hh states.dat.h
+	$(CXX) -c $<
+
+
+states-code.cc: states.dat states-tmpl.cc states-code.hh
+	../perfect_hash.py --splitby '|' --keycol 2 states.dat states-tmpl.cc
+
+
+states.dat.h: states.dat
+	./mk_header.py >$@
+
+
+clean:
+	rm lookup *.o states.dat.h states-code.cc
+
+
+test:
+	./lookup 'NY'
+	./lookup 'QW'

+ 24 - 0
components/rtgui/utils/perfect_hash/example-C++/main.cc

@@ -0,0 +1,24 @@
+
+#include <iostream>
+#include <string>
+using namespace std;
+
+#include "states-code.hh"
+
+
+int main (int argc, char *argv[])
+{
+  if (argc != 2) {
+    printf ("Usage: %s <abbreviation>\n", argv[0]);
+    return 2;
+  }
+
+  string abbr = argv[1];
+
+  State s(abbr);
+
+  cout << "The state of " << s.name ()
+       << " has a population of " << 1e-6 * s.population () << " million.\n";
+  
+  return 0;
+}

+ 10 - 0
components/rtgui/utils/perfect_hash/example-C++/mk_header.py

@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+for line in file('states.dat'):
+    line = line.strip()
+    if line.startswith('#'):
+        continue
+    
+    row = tuple(entry.strip() for entry in line.split('|'))
+
+    print '  { "%s", "%s", %s },' % row 

+ 19 - 0
components/rtgui/utils/perfect_hash/example-C++/states-code.hh

@@ -0,0 +1,19 @@
+
+
+#include <string>
+using namespace std;
+
+
+class State
+{
+public:
+  State (const string abbr);
+
+  string name () const { return nam; };
+  int population () const { return pop; };
+
+private:
+  string nam;
+  int pop;
+};
+

+ 55 - 0
components/rtgui/utils/perfect_hash/example-C++/states-tmpl.cc

@@ -0,0 +1,55 @@
+
+#include <string.h>
+
+#include <iostream>
+
+#include "states-code.hh"
+
+static struct {
+  char *name;
+  char *abbr;
+  int pop;
+} states[$NK] = {
+#include "states.dat.h"
+};
+
+static int T1[] = { $S1 };
+
+static int T2[] = { $S2 };
+
+static int G[] = { $G };
+
+static int hash_g (const char *key, const int *T)
+{
+  int i, sum = 0;
+  
+  for (i = 0; key[i] != '\0'; i++) {
+    sum += T[i] * key[i];
+    sum %= $NG;
+  }
+  return G[sum];
+}
+
+static int perfect_hash (const char *key)
+{
+  if (strlen (key) > $NS)
+    return 0;
+  
+  return (hash_g (key, T1) + hash_g (key, T2)) % $NG;
+}
+
+State::State (const string abbr)
+{
+  int hash_value = perfect_hash (abbr.c_str ());
+  
+  if (hash_value < $NK &&
+      strcmp(abbr.c_str (), states[hash_value].abbr) == 0)
+    {
+      nam = states[hash_value].name;
+      pop = states[hash_value].pop;
+    }
+  else
+    {
+      cerr << "'" << abbr << "' is not an abbreviation for a state\n";
+    }
+}

+ 52 - 0
components/rtgui/utils/perfect_hash/example-C++/states.dat

@@ -0,0 +1,52 @@
+# Name         | Abr  | Population
+#--------------+------+---------
+Alabama        | AL   |  4335400
+Alaska         | AK   |   611500
+Arizona        | AZ   |  4664600
+Arkansas       | AR   |  2531000
+California     | CA   | 33198100
+Colorado       | CO   |  3930700
+Connecticut    | CT   |  3271100
+Delaware       | DE   |   736900
+Florida        | FL   | 15012200
+Georgia        | GA   |  7562200
+Hawaii         | HI   |  1188400
+Idaho          | ID   |  1221500
+Illinois       | IL   | 11981700
+Indiana        | IN   |  5882500
+Iowa           | IA   |  2854700
+Kansas         | KS   |  2603200
+Kentucky       | KY   |  3921000
+Louisiana      | LA   |  4361200
+Maine          | ME   |  1243700
+Maryland       | MD   |  5122400
+Massachusetts  | MA   |  6133500
+Michigan       | MI   |  9825100
+Minnesota      | MN   |  4704200
+Mississippi    | MS   |  2739700
+Missouri       | MO   |  5421400
+Montana        | MT   |   886400
+Nebraska       | NE   |  1661400
+Nevada         | NV   |  1828700
+New Hampshire  | NH   |  1179100
+New Jersey     | NJ   |  8078300
+New Mexico     | NM   |  1738700
+New York       | NY   | 18197800
+North Carolina | NC   |  7483100
+North Dakota   | ND   |   640000
+Ohio           | OH   | 11197900
+Oklahoma       | OK   |  3328100
+Oregon         | OR   |  3266800
+Pennsylvania   | PA   | 12044200
+Rhode Island   | RI   |   987000
+South Carolina | SC   |  3781800
+South Dakota   | SD   |   738500
+Tennessee      | TN   |  5398200
+Texas          | TX   | 19274300
+Utah           | UT   |  2071500
+Vermont        | VT   |   590400
+Virginia       | VA   |  6768400
+Washington     | WA   |  5674900
+West Virginia  | WV   |  1813200
+Wisconsin      | WI   |  5224500
+Wyoming        | WY   |   479500

+ 26 - 0
components/rtgui/utils/perfect_hash/example-PyModule/Makefile

@@ -0,0 +1,26 @@
+
+
+CC = gcc -Wall
+
+
+stations.so: stationsmodule.c stations.dat.h stations-code.h
+	$(CC) -shared -fPIC -I/usr/local/include/python2.5 \
+            -o stations.so stationsmodule.c
+
+
+stations.dat.h: stations.dat
+	sed <$< >$@ -e 's:\([^,]*\),\([^,]*\):  { "\1", "\2" },:'
+
+
+stations-code.h: stations.dat stations-tmpl.h
+	../perfect_hash.py --trails 2 $^
+
+
+clean:
+	rm stations-code.h stations.dat.h stations.so
+
+
+test:
+	python -c "import stations; print stations.locator('DL5BAC')"
+
+

+ 12 - 0
components/rtgui/utils/perfect_hash/example-PyModule/stations-tmpl.h

@@ -0,0 +1,12 @@
+
+#define NK  $NK       /* number of keys */
+#define NG  $NG       /* number of vertices */
+#define NS  $NS       /* elements in T */
+
+
+int G[] = { $G };
+
+int T1[] = { $S1 };
+
+int T2[] = { $S2 };
+

+ 500 - 0
components/rtgui/utils/perfect_hash/example-PyModule/stations.dat

@@ -0,0 +1,500 @@
+DL0WM,JO40HM
+DM4WDK,JO50OI
+M0GHZ,IO81VK
+ON2CP,JO21IG
+PI4UTR,JO22MC
+DO2YMH,JO41AT
+ON1GZ,JO20FW
+DL5QQ,JO32KB
+M0HKB,JO02OB
+ON4LBT,JO10WK
+SM7VTW,JO65QQ
+PA3AYD,JO21UU
+DO3LTK,JO43XS
+DC0NAC,JO43VI
+PD0LQQ,JO20VS
+DO1YMJ,JO31WS
+DL1EJL,JO31FS
+DG3TF,JO53IU
+ON1AEN,JO10VW
+DL1KDA,JO30FQ
+SM7LHI,JO65PO
+DG1EIP,JO31JL
+PD1AKT,JO22TA
+DN1GSK,JO62NL
+OQ1AEN,JO10VW
+DG9YIH/M,JO31TR
+G0UYC,JO02MR
+F1PGL,JO20IE
+DO1KNB,JO30NQ
+DL5NEN,JN59OP
+DL1RNO,JO62FK
+DO8EF,JO31KK
+DL6IY,JN49NI
+ON4NOK,JO21LO
+DO9MH,JO33QO
+PA0PTS,JO23TF
+G5LK,IO91SK
+DJ6XV,JO31LQ
+ON4ARF,JO10MV
+PE1OJB,JO22IN
+DH1BBO,JO42FS
+M1DNJ,JO01GJ
+PA0BVD,JO23TF
+ON1CJQ,JO10OV
+DL2NFX,JN59JU
+DL4HG,JO53CM
+DG3BEO,JO43JF
+OZ4EDR,JO75JF
+DD1LT/P,JO44TK
+G4OXD,IO91UW
+DG1KZF,JO31RN
+DO2YPB,JO41JR
+DO3JJ,JO31QM
+DO5YLM,JO42GA
+DL2IAN,JN49BC
+PA0ME,JO22OB
+DC5PN,JN49HV
+PA9JP,JO32MS
+PD5RD,JO21IT
+PE1PQV,JO32JG
+OZ3TT,JO66CB
+DO9KS,JO43CE
+DJ8MS/P,JO63CT
+ON4KBE,JO20BI
+PE1JVV,JO21GV
+DH0EAQ,JO31IK
+DG9RCI,JN59PH
+DO6UWE/P,JO31OI
+DB7LG,JO44TH
+DD5JK,JO31RO
+DG6LSW,JO44SP
+M1MGD,IO91VC
+DL6YAU,JO44PJ
+PE1OLM,JO23TF
+DG0DRF,JO71JJ
+DG3YCB,JO41KV
+DF7JS,JO31JM
+OZ2NAC,JO55RT
+DJ5JD,JO33OO
+PA3DHR,JO21DU
+PE2JMR,JO33HG
+OZ1XAT/A,JO55UL
+PA3GKH,JO32HK
+G4DCJ,JO02IT
+DL4NAC,JN59SV
+DF0DS,JO31RM
+GW7SMV,IO81LN
+DO1AYJ,JO50SU
+DL0BAC,JO30BS
+DL0JRR,JO31CT
+OZ7HAM,JO65CL
+DK0ALK,JN38TD
+DO6DIB,JO43DA
+PA3GTC,JO32LR
+DD1LI,JO43WO
+DG9ACT/P,JO42QH
+PE1PMG,JO31BH
+SK7OL,JO66NC
+DH0JB,JO31CH
+OQ1ARQ,JO10VX
+DD7ZT,JO40DH
+DL1JJ,JO31IA
+DL1EEX,JO31MA
+ON4CDF,JO21EE
+DL0SE,JO31PG
+DO3YY,JO31QM
+DK0HC,JO40OQ
+DC8BQ,JO31KE
+DG1LAR,JO43UP
+OZ/DL0IZ/P,JO45GD
+DG3TD,JO44GQ
+DL6OBH,JO42QI
+PA0JCS,JO21DN
+DG0OJG,JO50MX
+DO1KFB,JO30CS
+SM60EW,JO67DA
+G4MRS/P,JO01MU
+DL5DBM,JO32WO
+DK3BM,JO42LH
+DD9DV,JO31TO
+DO1DQ,JO31TL
+OZ5AEK,JO55XO
+DG1YAR,JO41CR
+OO6LY,JO21LH
+DL1PR,JO30JS
+DL5ZAB,JO40HC
+DO1MGN,JO50DO
+SM7UPF,JO65TO
+DO1NNN,JO50VF
+DK5BD,JO42IX
+DL3OCA,JO42VH
+HB9MPX,JN47RJ
+DG4KAS,JO30DU
+DF1UF,JN49HK
+DC6GF/P,JN47NX
+DG7ES,JN68GI
+DF0NF,JO44UH
+DG8EKI,JO31MI
+OZ9CLN,JO56CE
+SK7MW,JO65MJ
+DL9ECA,JO31CQ
+DF9IC,JN48IW
+PD9FJ,JO23KE
+DL4LBO,JO43XT
+DF0WD,JO42FD
+DH4PSG,JO31NN
+LA0BY,JO59IX
+DJ5FK,JO42SH
+DO1ASM,JO50LQ
+DL9KCM,JO30IS
+DG6MBS,JO41AH
+OZ2SYV,JO54RS
+DL0HMS,JO42MC
+DL2PZ,JN49DW
+DG5NEP/P,JO50VF
+SM6VKC,JO68CG
+DF8AA/P,JO71AA
+PA1WM,JO21WW
+DO3BTL,JO43HB
+PA3GGN,JO21LU
+DF1VW,JN39HJ
+DJ5KX,JO30PQ
+ON1LPA,JO20XO
+DJ5QW,JO32SF
+G4AJC,IO91VJ
+OZ7P,JO45SQ
+G4MRS,JO02PB
+PD0ZX,JO22QF
+DB5BR,JO42FS
+DO1JRA,JO42GF
+DL1DUF,JO62EJ
+DO2NHD,JO40MB
+DG6DDE,JO31UM
+PA3FBP,JO33GB
+DC1GUN,JN68GG
+DO2BO,JO33RM
+OZ6AQ,JO44UX
+OZ1QQ,JO47XG
+DG1YBT,JO32QD
+DL9YEY,JO41GV
+DG1YIV,JO42HF
+DB2WD,JN39VV
+DF0UKW,JN49HN
+OZ1BEF/P,JO46SB
+PE1ISU,JO21WD
+DO1KOH,JO30HR
+DK9SS,JN48OM
+PE1OPK,JO23UE
+DG3GAQ,JN48GE
+DO2FX,JO40LH
+SK7BT,JO65MO
+OZ1FHU,JO55SR
+SK6QW,JO68WR
+DL4FBN,JO30WC
+DG3FCT,JO41RB
+OE2SCM,JN67OV
+PA0ZM,JO32GK
+DL0MQ,JO41EV
+DB3WR,JO31DG
+ON2BFV,JO11XA
+DJ5DM,JO31FF
+G6FPQ,IO91XI
+DJ0VZ,JO30GL
+OO2WIM,JO20OR
+DG7RZ/P,JN59WK
+DL5QN,JO42HC
+DC9XX,JO43QR
+SM7SLU,JO65ML
+F1PYW,JN38UP
+DG2NJ,JN68OL
+DJ5KM,JO42GA
+DL3TS,JO30PX
+DG4YIE/P,JO41PU
+DL0RSH,JO43SV
+PE1RYU,JO21GU
+DJ3QB,JO32MF
+DG4KBY/P,JO42CW
+PA3GSX,JO32DM
+DG1YRT,JO41KW
+DG9BEY,JO42AH
+PA3EXO,JO32GW
+PE1OPH,JO22XF
+DO9FB,JN49BP
+F0EUE,JN29VM
+G4RRA/P,IO70XR
+DL0EDD,JO31IF
+SM7MRL,JO66KC
+DK5JM,JO43QS
+DJ3NU,JO31SL
+DH6YMC,JO32MF
+DL1DAX,JO31RM
+DC4KM,JO30XO
+F1TUE,JN38DR
+DO4ME,JO43KC
+ON7CC,JO10XM
+DL1PBC,JO30VJ
+DL3IAE,JN49DE
+DL1SDN,JN48PP
+DL4ANT,JN49LF
+DH1NHI,JO50VF
+DO1BR,JO42AE
+G4ODA,IO92WS
+DB2DJ,JO31RM
+DL8LAH,JO44QQ
+DH9NBB,JN49WS
+F1LPV,JO10NP
+DL3SF,JO32MF
+SM7VXT,JO65NU
+DL4LCA/P,JO44XF
+DL3FDL,JO40KR
+SM7XEN,JO65RL
+DL6ABO,JO52GH
+EI7IW,IO63SS
+DC1QU,JO31TW
+DG0OCW,JO50CT
+SM7XWM,JO86AJ
+ON2MRT,JO20MX
+DA0GSN,JO31HB
+DL8FBC,JO41UF
+F1DBN/P,JO00WT
+DJ6CB,JO42JW
+DL1SUZ,JO53UN
+DJ5NU,JO31QH
+DL0SOP,JO54WC
+DO1MGN/P,JO50AN
+OK1BYR,JN79IP
+PD0RAA,JO22WK
+DJ9DL,JO31NC
+DK5WO,JO30AS
+OZ8FYN,JO55EJ
+DO1FDR,JO41PD
+ON2BIV,JO10RX
+ON4AEO,JO10OW
+DL4MB,JN49FA
+GW4HBZ/P,IO83GC
+OZ1BEF,JO46OE
+PE0NYJ,JO21VT
+DO3LBP,JO43MW
+DB3BW,JO42AC
+DF6YL,JO31WS
+DP0RFU,JO32LS
+DF4BV,JO43RH
+DJ6GV,JO52HG
+DG7KAQ,JO30FS
+DH1YPH,JO31VL
+SM7JUQ,JO65PO
+DG7ACF,JO42UI
+DG6NBL,JN59LL
+OK1MCS,JN69QR
+DL1REM,JO32MF
+DN1RDT,JN59WK
+OZ3FYN/P,JO55BJ
+DB0GSN,JO31JC
+DC1GUN/P,JN68GI
+DJ1DH/P,JO53BG
+DO1RSG/P,JN68KX
+PD0FFU,JO20UU
+DO8DW,JO31SO
+DL8II,JN49GP
+PA3DRL,JO21PS
+DG8LG,JO44VP
+PD0EBF,JO21LQ
+OZ9BO,JO46HE
+DO3NML,JN59SV
+DJ3BP,JO42CX
+F6IRS,JN38VN
+F5SMZ,JN39EJ
+GM1TDU,IO87WE
+DL5BAC,JO43LG
+DO7OCH,JO51AT
+DL1HRY,JO61AD
+DK7VA,JO32MK
+SM7JPI,JO75DW
+DL0GC,JO31CQ
+M1IFT,IO93NL
+DF5AY,JN49DX
+DG1IHH,JN49GJ
+DO5BRH,JO43CE
+DK6AJ,JO52GH
+DL0NF,JN59PL
+DG1BHM,JO43PC
+DK3RV,JO31DG
+DD8EI,JO31NC
+PD2PL,JO22HD
+DL0GL,JO31LN
+DC1PJA,JN49DV
+PD2GCM,JO21ET
+SI7GM,JO65MO
+DG6MOG,JO52XN
+OQ4CJU,JO20PS
+DG1DPN,JO31RL
+DK0BA,JO43NF
+DL2HQ,JN48FX
+PA4PS,JO33GH
+DK0EE,JN58TG
+DD9PL,JN49CN
+PB0AOK,JO32IH
+DC2OOO,JN39NI
+DL0NS,JO31IE
+ON4BAK,JO31PA
+G4DCV,IO91OF
+DG4FFF,JO40FA
+G3BNE,JO01BJ
+DO2GN,JO31PM
+DD7PA/P,JN49LM
+OZ0A/P,JO55UL
+DL8BEV,JO43JH
+DJ8UV,JO31OF
+PE1PMV,JO32JG
+DL8AX,JO31ID
+PE1RER,JO22SA
+PD0RKC,JO33AD
+DC4ASK,JO31MI
+DG1YCF,JO42KH
+SK7PL,JO76DJ
+M1MHZ,IO92WV
+DF9PX/P,JO30JF
+DG0OZ,JO50LU
+DB1BMN/P,JO43HA
+DH2UD/P,JO44XS
+OZ5AGJ,JO56DF
+OZ3AEV,JO55WR
+PA1JAN,JO32KV
+PE7MO,JO32KR
+LA7M,JO48KK
+PA1TX,JO32JG
+OZ7DAL,JO56IE
+PE1PED,JO22QE
+DL0WH,JN49HN
+DL9KI,JO42GE
+M0AIJ,IO92PA
+DG0CAL/P,JO31BC
+DG1YFF,JO42IG
+OZ4DR,JO55WL
+G8RWG,JO01BN
+OZ3RIN,JO55VK
+SM7VXS,JO65UV
+DL9EBI,JO31IE
+PD5FDV,JO21HV
+DL5XB,JO43UL
+DJ9IQ,JO30OI
+PE1NNX,JO22JN
+DB2YC,JO32OF
+PA5WT,JO22HG
+DO2PK,JO41NW
+PE1BVW,JO21DO
+DL0TS,JO40FC
+DB9KR,JO41DQ
+DO1ZB,JO64II
+DO4YPM,JO32QI
+G0VJG,JO01BL
+DD2YCS,JO43FE
+DO7MH,JO31MT
+G3JHM,IO91LC
+DL8FAJ,JO51AD
+DG4FR,JO31OJ
+ON1DNF,JO20NU
+DO4FMK,JO40MF
+PI4THT,JO32KF
+DK4LI,JO44WQ
+DD3FU,JO40IE
+DF1LON/P,JO31LH
+DL2ARD/P,JO60AR
+DH9YBC,JO42HE
+G3OHC,IO93KS
+DK0HF,JO42IF
+DF6QB,JO31WW
+DO3HN,JO31LK
+M3RCV,JO01AL
+DL0SAT,JO41XO
+DD7PC,JN49AX
+DL2LSM,JO61HH
+PA3HHT,JO22QC
+PD2OPA,JO21BT
+DL0VR,JO31MI
+EI3GE,IO63XD
+DF9CY,JO54AL
+DL1AH,JO42TX
+DL1PW,JN49DV
+DC9CZ,JO42GA
+PA3FJY/P,JO32FI
+DG5BGB,JO43HB
+ON7LAO,JO20CK
+DG0SY,JO54VC
+DK5KC,JO30DS
+DG6YJ,JO32RB
+OO4BAX,JO21IH
+DO1LNK,JO53EK
+DJ3LE,JO44SK
+DO1YCI,JO31NO
+DJ8TA,JO41BU
+DL8BAV,JO43MF
+DO1RSG,JN68ET
+DO1PIA,JO31PM
+DL1AUW/P,JO51CH
+DL0VV,JO64AD
+DL3JAN/P,JO60KS
+ON50ZTM,JO10UV
+PA3GHZ,JO21OI
+DL2SDU,JN48XT
+DG4YFT,JO31OR
+G0UIQ,JO02PW
+DF9PX,JN49HU
+DG8FAY,JO40GD
+DL9LBH,JO30MP
+DG5YHK,JO31SR
+DC2GY/P,JN48DS
+PE1PZS,JO21DV
+ON4PS,JO20KQ
+PE1PWM,JO22FE
+DL2VB/P,JO31KP
+DG8BX/P,JO43NA
+DK4FG,JO40EM
+DO8BAF/P,JN59WK
+OK1MSM/P,JN69PR
+DC2GY,JN48BQ
+DK2LR,JN57KO
+DH3UN,JO31TL
+DF0SB,JN48GE
+ON4CBR,JO10OU
+DB3VE,JN39KK
+DO2YTM,JO42GA
+DJ9CN,JO43DA
+M3HKK/P,JO01BB
+DK8ZB,JN49KW
+DC2AM,JO43WL
+DF7KF,JO30GU
+DC7KG,JO30LW
+SK7CY,JO65RJ
+DH6OBN/P,JO42UJ
+SK7HR,JO77HM
+ON4BAR,JO10MV
+DH8OH,JO51AT
+DL5OAK,JO52AK
+DG1DX,JO31SL
+DL0HEU,JN47NX
+DL1FX,JN49HS
+DN1BE,JO42AH
+G4ZTR,JO01KW
+DG3YY,JO31QM
+DK4WH/P,JN49BH
+OK1UEM,JO60TH
+PE1LWJ,JO22VJ
+OZ0XX,JO54RS
+DO1ON,JO51HR
+DK0DH,JO31QL
+DJ9JY,JO31JM
+DG1FDX,JN49LP
+DG0CCD,JO52TC
+DL5NAV,JO33TF
+DL4KCA,JO31JX
+DG6NDK,JN59GN
+DO9BC,JN48QP
+DK1HW,JO42TG
+DC4MP,JO31MI
+ON4CIN,JO11UB
+LA2CFA,JO48JL
+DH2SAV,JN48QU
+PE1ONM,JO32KR
+M5AEH,IO93BS

+ 69 - 0
components/rtgui/utils/perfect_hash/example-PyModule/stationsmodule.c

@@ -0,0 +1,69 @@
+
+#include <Python.h>
+
+#include "stations-code.h"
+
+static struct {
+  char *callsign;
+  char *locator;
+} station_list[] = {
+#include "stations.dat.h"
+};
+
+static int hash_f (const char *s, const int *T)
+{
+  register int i, sum = 0;
+
+  for (i = 0; s[i] != '\0'; i++) {
+    sum += T[i] * s[i];
+    sum %= NG;
+  }
+  return sum;
+}
+
+static int perf_hash (const char *k)
+{
+  if (strlen (k) > NS)
+    return 0;
+  
+  return (G[ hash_f(k, T1) ] + G[ hash_f(k, T2)] ) % NG;
+}
+
+static int getlocator (char *locator, const char *callsign)
+{
+  int hashval = perf_hash (callsign);
+  
+  if (hashval < NK && strcmp(callsign, station_list[hashval].callsign) == 0) {
+    strcpy (locator, station_list[hashval].locator);
+    return 1;
+  }
+  return 0;
+}
+
+static PyObject *
+stations_locator(PyObject *self, PyObject *args)
+{
+  const char *callsign;
+  char locator[6];
+  
+  if (!PyArg_ParseTuple(args, "s", &callsign))
+    return NULL;
+  
+  return Py_BuildValue("s", (getlocator (locator, callsign) == 1) ?
+		       locator : NULL);
+}
+
+static PyMethodDef StationsMethods[] = {
+
+    {"locator",  stations_locator, METH_VARARGS,
+     "Get locator from callsign."},
+
+    {NULL, NULL, 0, NULL}        /* Sentinel */
+};
+
+
+PyMODINIT_FUNC
+initstations(void)
+{
+  (void) Py_InitModule("stations", StationsMethods);
+}

+ 28 - 0
components/rtgui/utils/perfect_hash/example-PyModule/test.py

@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+import sys
+from timeit import Timer
+from stations import locator
+
+call = sys.argv[1]
+print repr(call)
+D = {}
+
+for line in file('stations.dat'):
+    c, l = [x.strip() for x in line.split(',')]
+    D[c] = l
+
+def test1(c):
+    return D[c]
+
+print repr(test1(call))
+t = Timer("test1(%r)" % call, "from __main__ import test1")
+print t.timeit()
+
+# -----
+
+def test2(c):
+    return locator(c)
+
+print repr(test2(call))
+t = Timer("test2(%r)" % call, "from __main__ import test2")
+print t.timeit()

+ 40 - 0
components/rtgui/utils/perfect_hash/example-Python/Graph.py

@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+"""
+This example shows how to use the class Graph.
+
+The class implements a graph with 'N' vertices.  First, you connect the
+graph with edges, which have a desired value associated.  Then the vertex
+values are assigned, which will fail if the graph is cyclic.  The vertex
+values are assigned such that the two values corresponding to an edge add
+up to the desired edge value (mod N).
+"""
+import sys
+
+sys.path.append('..')
+from perfect_hash import Graph
+
+G = Graph(3)
+assert G.assign_vertex_values() == True
+    
+# Now we make an edge between vertex 0 and 1 with desired edge value 2:
+G.connect(0, 1, 2)
+
+# Make another edge 1:2 with desired edge value 1:
+G.connect(1, 2, 1)
+    
+# The graph is still acyclic, and assigning values works:
+assert G.assign_vertex_values() == True
+assert G.vertex_values == [0, 2, 2]
+    
+# What do these values mean?
+# When you add the values for edge 0:1 you get 0 + 2 = 2, as desired.
+# For edge 1:2 you add 2 + 2 = 4 = 1 (mod 3), as desired.
+
+# Adding edge 0:2 produces a loop, so the graph is no longer acyclic.
+# Assigning values fails.
+G.connect(0, 2, 0)
+
+assert G.assign_vertex_values() == False
+
+
+print 'OK'

+ 15 - 0
components/rtgui/utils/perfect_hash/example-Python/Makefile

@@ -0,0 +1,15 @@
+
+
+all:
+	true
+
+
+clean:
+	true
+
+
+test:
+	./generate_hash.py
+	./PerfHash.py
+	./Graph.py
+

+ 40 - 0
components/rtgui/utils/perfect_hash/example-Python/PerfHash.py

@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+"""
+This example shows how to use the class PerfHash.
+
+This class is designed for creating perfect hash tables at run time,
+which should be avoided, in particulat inserting new keys is
+prohibitively expensive since a new perfect hash table needs to be
+constructed.  However, this class can be usefull for testing.
+
+For practical programming purposes in Python the class PerfHash
+should never be used because Python's built-in dictionary is very
+efficient and always faster than PerfHash.
+"""
+
+import sys
+
+sys.path.append('..')
+from perfect_hash import PerfHash
+
+
+month = dict(zip('jan feb mar apr may jun jul aug sep oct mov dec'.split(),
+                 range(1, 13)))
+
+d = PerfHash(month)
+
+
+for m in month:
+    assert month[m] == d[m]
+
+d[True] = False
+
+assert d[True] == False
+
+for i in xrange(10):  # very expensive
+    d[i] = 2*i*i + 3*i -7
+
+assert d[4] == 37
+
+
+print 'OK'

+ 38 - 0
components/rtgui/utils/perfect_hash/example-Python/generate_hash.py

@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+"""
+This example shows how to use the function generate_hash.
+
+generate_hash(kdic, Hash)
+
+returns hash functions f1 and f2, and G for a perfect minimal hash.
+Input is dictionary 'kdic' with the keys and desired hash values.
+'Hash' is a random hash function generator, that means Hash(N) returns a
+returns a random hash function which returns hash values from 0..N-1.
+"""
+
+import sys
+import random, string
+
+sys.path.append('..')
+from perfect_hash import generate_hash
+
+
+
+month = dict(zip('jan feb mar apr may jun jul aug sep oct mov dec'.split(),
+                 range(1, 13)))
+
+def mkRandHash(N):
+    """
+    Return a random hash function which returns hash values from 0..N-1.
+    """
+    junk = "".join(random.choice(string.letters + string.digits)
+                   for i in xrange(10))
+    return lambda key: hash(junk + str(key)) % N
+
+
+f1, f2, G = generate_hash(month, mkRandHash)
+
+for k, h in month.items():
+    assert h == ( G[f1(k)] + G[f2(k)] ) % len(G)
+
+print 'OK'

+ 31 - 0
components/rtgui/utils/perfect_hash/example1-C/Makefile

@@ -0,0 +1,31 @@
+
+CC = gcc -Wall
+
+
+lookup: main.o states-code.o
+	$(CC) -o $@ $^
+
+
+main.o: main.c states-code.h states.dat.h
+	$(CC) -c $<
+
+
+states-code.o: states-code.c states-code.h
+	$(CC) -c $<
+
+
+states-code.c: states.dat states-tmpl.c
+	../perfect_hash.py -vvvv --splitby '|' --keycol 2 $^
+
+
+states.dat.h: states.dat
+	./mk_header.py >$@
+
+
+clean:
+	rm lookup *.o states.dat.h states-code.c
+
+
+test:
+	./lookup 'NY'
+	./lookup 'QW'

+ 33 - 0
components/rtgui/utils/perfect_hash/example1-C/main.c

@@ -0,0 +1,33 @@
+
+#include <stdio.h>
+
+#include "states-code.h"
+
+struct {
+  char *name;
+  char *abbr;
+  int pop;
+} states[] = {
+#include "states.dat.h"
+};
+
+
+int main (int argc, char *argv[])
+{
+  if (argc != 2) {
+    printf ("Usage: %s <abbreviation>\n", argv[0]);
+    return 2;
+  }
+
+  char *abbr = argv[1];
+  int hashval;
+  
+  if ((hashval = has_key(abbr)) == -1)
+    printf ("'%s' is not an abbreviation for a state.\n", abbr);
+  else
+    printf ("The state of %s has a population of %g million.\n",
+	    states[hashval].name,
+	    1e-6 * states[hashval].pop);
+  
+  return 0;
+}

+ 10 - 0
components/rtgui/utils/perfect_hash/example1-C/mk_header.py

@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+for line in file('states.dat'):
+    line = line.strip()
+    if line.startswith('#'):
+        continue
+    
+    row = tuple(entry.strip() for entry in line.split('|'))
+
+    print '  { "%s", "%s", %s },' % row 

+ 6 - 0
components/rtgui/utils/perfect_hash/example1-C/states-code.h

@@ -0,0 +1,6 @@
+
+
+/* Return hash value of abbreviation 'abbr' if found, -1 otherwise */
+int has_key (const char *abbr);
+
+

+ 42 - 0
components/rtgui/utils/perfect_hash/example1-C/states-tmpl.c

@@ -0,0 +1,42 @@
+
+#include <string.h>
+
+#include "states-code.h"
+
+
+static int T1[] = { $S1 };
+
+static int T2[] = { $S2 };
+
+static int G[] = { $G };
+
+static char *K[] = { $K };
+
+static int hash_g (const char *key, const int *T)
+{
+  int i, sum = 0;
+  
+  for (i = 0; key[i] != '\0'; i++) {
+    sum += T[i] * key[i];
+    sum %= $NG;
+  }
+  return G[sum];
+}
+
+static int perfect_hash (const char *key)
+{
+  if (strlen (key) > $NS)
+    return 0;
+  
+  return (hash_g (key, T1) + hash_g (key, T2)) % $NG;
+}
+
+int has_key (const char *abbr)
+{
+  int hash_value = perfect_hash (abbr);
+  
+  if (hash_value < $NK && strcmp(abbr, K[hash_value]) == 0)
+    return hash_value;
+  
+  return -1;
+}

+ 52 - 0
components/rtgui/utils/perfect_hash/example1-C/states.dat

@@ -0,0 +1,52 @@
+# Name         | Abr  | Population
+#--------------+------+---------
+Alabama        | AL   |  4335400
+Alaska         | AK   |   611500
+Arizona        | AZ   |  4664600
+Arkansas       | AR   |  2531000
+California     | CA   | 33198100
+Colorado       | CO   |  3930700
+Connecticut    | CT   |  3271100
+Delaware       | DE   |   736900
+Florida        | FL   | 15012200
+Georgia        | GA   |  7562200
+Hawaii         | HI   |  1188400
+Idaho          | ID   |  1221500
+Illinois       | IL   | 11981700
+Indiana        | IN   |  5882500
+Iowa           | IA   |  2854700
+Kansas         | KS   |  2603200
+Kentucky       | KY   |  3921000
+Louisiana      | LA   |  4361200
+Maine          | ME   |  1243700
+Maryland       | MD   |  5122400
+Massachusetts  | MA   |  6133500
+Michigan       | MI   |  9825100
+Minnesota      | MN   |  4704200
+Mississippi    | MS   |  2739700
+Missouri       | MO   |  5421400
+Montana        | MT   |   886400
+Nebraska       | NE   |  1661400
+Nevada         | NV   |  1828700
+New Hampshire  | NH   |  1179100
+New Jersey     | NJ   |  8078300
+New Mexico     | NM   |  1738700
+New York       | NY   | 18197800
+North Carolina | NC   |  7483100
+North Dakota   | ND   |   640000
+Ohio           | OH   | 11197900
+Oklahoma       | OK   |  3328100
+Oregon         | OR   |  3266800
+Pennsylvania   | PA   | 12044200
+Rhode Island   | RI   |   987000
+South Carolina | SC   |  3781800
+South Dakota   | SD   |   738500
+Tennessee      | TN   |  5398200
+Texas          | TX   | 19274300
+Utah           | UT   |  2071500
+Vermont        | VT   |   590400
+Virginia       | VA   |  6768400
+Washington     | WA   |  5674900
+West Virginia  | WV   |  1813200
+Wisconsin      | WI   |  5224500
+Wyoming        | WY   |   479500

+ 22 - 0
components/rtgui/utils/perfect_hash/example2-C/Makefile

@@ -0,0 +1,22 @@
+
+CC = gcc -Wall
+
+a.out: main.c keys.code.h
+	$(CC) $<
+
+
+keys.code.h: keys.dat keys.tmpl.h
+	../perfect_hash.py $^
+
+
+keys.dat:
+	./mk_rnd_keys.py 100 >keys.dat
+
+
+clean:
+	rm keys.dat keys.code.h a.out
+
+
+test:
+	./a.out
+

+ 13 - 0
components/rtgui/utils/perfect_hash/example2-C/keys.tmpl.h

@@ -0,0 +1,13 @@
+
+#define NK  $NK       /* number of keys */
+#define NG  $NG       /* number of vertices */
+#define NS  $NS       /* length of array T1 and T2 */
+
+int T1[] = { $S1 };
+
+int T2[] = { $S2 };
+
+int G[] = { $G };
+
+char *K[] = { $K };
+

+ 51 - 0
components/rtgui/utils/perfect_hash/example2-C/main.c

@@ -0,0 +1,51 @@
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "keys.code.h"
+
+int hash_g (char *s, int *T)
+{
+  int i, f = 0;
+
+  for (i = 0; s[i] != '\0'; i++) {
+    f += T[i] * s[i];
+    f %= NG;
+  }
+  return G[f];
+}
+
+int hash (char *k)
+{
+  if (strlen (k) > NS)
+    return 0;
+  
+  return (hash_g (k, T1) + hash_g (k, T2)) % NG;
+}
+
+bool has_key (char *k)
+{
+  int h = hash (k);
+  
+  return h < NK && strcmp(k, K[h]) == 0;
+}
+
+int main ()
+{
+  int i;
+
+  char *junk = "acnhuvn5yushvghnw7og5siuhgsiuhnglsh45vgghwn";
+
+  assert (has_key(junk) == 0);
+  assert (hash(junk) == 0);
+  
+  for (i = 0; i < NK; i++) {
+    assert (has_key(K[i]) == true);
+    assert (hash(K[i]) == i);
+  }
+  puts ("OK");
+  
+  return 0;
+}

+ 17 - 0
components/rtgui/utils/perfect_hash/example2-C/mk_rnd_keys.py

@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+
+# ./mk_rnd_keys.py 10000 | sort | uniq | shuf >keywords.txt
+
+import sys
+from random import choice, randint
+from string import digits, uppercase, lowercase
+
+def key():
+    return ''.join(choice(uppercase + lowercase + digits)
+                   for i in xrange(randint(6, 20)))
+
+N = int(sys.argv[1])
+
+
+for n in xrange(N):
+    print key()

+ 23 - 0
components/rtgui/utils/perfect_hash/graph/Makefile

@@ -0,0 +1,23 @@
+
+
+
+animals.ps: animals.dot
+	neato -Tps $< -Gstart=100 -o $@
+
+
+animals.dot: animals.py
+	./py2dot -l $< -o $@
+
+
+animals.py: ../animals.txt
+	../perfect_hash.py $< >$@
+
+
+clean:
+	rm animals.py animals.dot animals.ps
+
+
+test:
+	true
+
+

+ 4 - 0
components/rtgui/utils/perfect_hash/graph/example-pipeline

@@ -0,0 +1,4 @@
+#!/bin/bash
+
+../perfect_hash.py ../animals.txt | ./py2dot | neato -Tps -Gstart=100 -o out.ps
+

+ 216 - 0
components/rtgui/utils/perfect_hash/graph/py2dot

@@ -0,0 +1,216 @@
+#!/usr/bin/env python
+
+class Graph:
+    def __init__(self, N):
+        self.N = N                     # number of vertices
+        
+        # maps a vertex number to the list of (vertices, edge value)
+        # to which it is connected by edges.
+        self.adjacent = [[] for n in xrange(N)]
+    
+    def connect(self, vertex1, vertex2, edge_value):
+        """
+        Connect 'vertex1' and 'vertex2' with an edge, with associated
+        value 'value'
+        """
+        # Add vertices to each other's adjacent list
+        self.adjacent[vertex1].append( (vertex2, edge_value) )
+        self.adjacent[vertex2].append( (vertex1, edge_value) )
+
+    def check(self):
+        """
+        See if vertex values add up to edge values (mod N).
+        """
+        for vertex in xrange(self.N):
+            for neighbor, edge_value in self.adjacent[vertex]:
+                assert (self.vertex_values[vertex] +
+                        self.vertex_values[neighbor]) % self.N == edge_value
+    
+    def calc_tree_sizes(self):
+        """
+        After running this method, the attribute size will contain a list,
+        which maps the vertices to the size of the tree that vertex belongs
+        to.
+        """
+        visited = self.N * [-1]  # -1 unvisited, otherwise the number of tree
+        treenum = 0
+        
+        # Loop over all vertices, taking unvisited ones as roots.
+        for root in xrange(self.N):
+            if visited[root] >= 0:
+                continue
+            
+            # explore tree starting at 'root'
+            # Stack of vertices to visit, a list of tuples (parent, vertex)
+            tovisit = [ (None, root) ]
+            while tovisit:
+                parent, vertex = tovisit.pop()
+                visited[vertex] = treenum
+                
+                # Loop over adjacent vertices, but skip the vertex we arrived
+                # here from the first time it is encountered.
+                skip = True
+                for neighbor, edge_value in self.adjacent[vertex]:
+                    if skip and neighbor == parent:
+                        skip = False
+                        continue
+                    
+                    if visited[neighbor] >= 0:
+                        # We visited here before, so the graph is cyclic.
+                        exit('Hmm, graph is cyclic.')
+                    
+                    tovisit.append( (vertex, neighbor) )
+                    
+            treenum += 1
+        
+        # maps the tree number to number of vertices within that tree
+        treesizes = treenum * [0]
+        for tree in visited:
+            treesizes[tree] += 1
+        
+        self.size = [treesizes[visited[v]] for v in xrange(self.N)]
+        
+        if verbose:
+            freq = (self.N+1) * [0]
+            for size in treesizes:
+                freq[size] += 1
+        
+            sys.stderr.write(' Size   Trees\n')
+            for i, f in enumerate(freq):
+                if f:
+                    sys.stderr.write('%5i %5i\n' % (i, f))
+                if i == minsize-1:
+                    sys.stderr.write('--------------\n')
+        
+    def write(self, fo, labels = False):
+        self.calc_tree_sizes()
+        
+        fo.write('graph G {\n'
+                 '  size = "8,8";\n'
+                 '  edge [color="#ff0000"]\n')
+        if labels:
+            fo.write('  node [color="#a0e0ee", style=filled];\n')
+            
+            for vertex, value in enumerate(self.vertex_values):
+                if self.size[vertex] < minsize: continue
+                fo.write('  { node [label="%i: %i"] v%i }\n' % (
+                    vertex, value, vertex))
+        else:
+            fo.write('  node [color="#3377a0", label="",\n'
+                     '        style=filled, shape=circle]\n')
+            
+        for vertex in xrange(self.N):          # edges
+            if self.size[vertex] < minsize: continue
+            for neighbor, edge_value in self.adjacent[vertex]:
+                if neighbor > vertex:  continue
+                fo.write('  v%i -- v%i%s;\n' %
+                         (vertex, neighbor,
+                          (' [label="%s: %i"]' % (K[edge_value], edge_value))
+                          if labels else ''))
+        fo.write('}\n')
+        fo.close()
+
+
+if __name__ == '__main__':
+    import sys
+    from optparse import OptionParser
+    
+    usage = "usage: %prog [options] [PYCODE]"
+    
+    description = """\
+Given the python code for a perfect hash function which was generated by
+perfect_hash.py, e.g. by '$ ../perfect_hash.py animals.txt >animals.py',
+this program will create the graph which was used in determining the
+perfect hash function.  The input python code may also be given to stdin.
+The output is saved as in the .dot format which is used by the Graphviz
+tools (see http://www.graphviz.org/) to generate a picture of the graph.
+"""
+
+    parser = OptionParser(usage = usage,
+                          description = description,
+                          prog = sys.argv[0])
+
+    parser.add_option("-l", "--labels",
+                      action  = "store_true",
+                      help    = "Be verbose")
+
+    parser.add_option("-m", "--minsize",
+                      action  = "store",
+                      default = 1,
+                      type    = "int",
+                      help    = "Include only trees in the output which "
+                                "have at least INT vertices. "
+                                "Default is %default, i.e. all trees are "
+                                "included within the output.",
+                      metavar = "INT")
+
+    parser.add_option("-o", "--output",
+                      action  = "store",
+                      help    = "Specify output FILE explicitly. "
+                                "Default, is stdout. ",
+                      metavar = "FILE")
+
+    parser.add_option("-v", "--verbose",
+                      action  = "store_true",
+                      help    = "Be verbose")
+    
+    options, args = parser.parse_args()
+    
+    if options.minsize > 0:
+        minsize = options.minsize
+    else:
+        parser.error("minimal size of trees has to be larger than zero")
+    
+    verbose = options.verbose
+    
+    if len(args) > 1:
+        parser.error("incorrect number of arguments")
+
+    # --------------------- end parsing and checking -----------------------
+    
+    if verbose:
+        sys.stderr.write('minsize (of trees): %i\n' % minsize)
+        sys.stderr.write('labels (in output): %s\n' % options.labels)
+
+    # ------------ input filehandle
+    
+    if len(args)==1:
+        try:
+            fi = file(args[0])
+        except IOError :
+            exit("Error: Can't open `%s' for reading." % args[0])
+    else:
+        fi = sys.stdin
+
+    # ------------ read input, i.e. execute code
+    
+    exec(fi.read())
+    
+    # ------------ make graph
+    
+    g = Graph(len(G))
+    g.vertex_values = G
+    for key, hashval in zip(K, H):
+        g.connect(hash_f(key, S1),
+                  hash_f(key, S2),
+                  hashval)
+    g.check()
+
+    # ------------ output filehandle
+    
+    if options.output:
+        try:
+            fo = file(options.output, 'w')
+        except IOError :
+            exit("Error: Can't open `%s' for writing." % options.output)
+    else:
+        fo = sys.stdout
+
+    # ------------ write output, i.e. generate .dot output
+
+    g.write(fo, options.labels)
+
+
+# Local Variables:
+# mode: python
+# End:

+ 870 - 0
components/rtgui/utils/perfect_hash/perfect_hash.py

@@ -0,0 +1,870 @@
+#!/usr/bin/env python
+"""
+Generate a minimal perfect hash function for the keys in a file,
+desired hash values may be specified within this file as well.
+A given code template is filled with parameters, such that the
+output is code which implements the hash function.
+Templates can easily be constructed for any programming language.
+
+The code is based on an a program A.M. Kuchling wrote:
+http://www.amk.ca/python/code/perfect-hash
+
+The algorithm the program uses is described in the paper
+'Optimal algorithms for minimal perfect hashing',
+Z. J. Czech, G. Havas and B.S. Majewski.
+http://citeseer.ist.psu.edu/122364.html
+
+The algorithm works like this:
+
+1.  You have K keys, that you want to perfectly hash against some
+    desired hash values.
+
+2.  Choose a number N larger than K.  This is the number of
+    vertices in a graph G, and also the size of the resulting table G.
+
+3.  Pick two random hash functions f1, f2, that return values from 0..N-1.
+
+4.  Now, for all keys, you draw an edge between vertices f1(key) and f2(key)
+    of the graph G, and associate the desired hash value with that edge.
+
+5.  Check if G is acyclic, i.e. has no loops; if no, go back to step 2.
+
+6.  Assign values to each vertex such that, for each edge, you can add
+    the values for the two vertices and get the desired (hash) value 
+    for that edge.  This task is easy, because the graph is acyclic.
+    This is done by picking a vertex, and assigning it a value of 0.
+    Then do a depth-first search, assigning values to new vertices so that
+    they sum up properly.
+
+7.  f1, f2, and vertex values of G now make up a perfect hash function.
+
+
+For simplicity, the implementation of the algorithm combines steps 5 and 6.
+That is, we check for loops in G and assign the vertex values in one procedure.
+If this procedure succeeds, G is acyclic and the vertex values are assigned.
+If the procedure fails, G is cyclic, and we go back to step 2, replacing G
+with a new graph, and thereby discarding the vertex values from the failed
+attempt.
+"""
+__author__  = 'Ilan Schnell <ilanschnell@gmail.com>, 2008 (and AMK 2000)'
+__license__ = 'GNU GPL 2'
+__version__ = '0.1'
+
+
+import sys, random, string, cStringIO, StringIO
+
+verbose = False
+trails = 5
+
+
+class Graph:
+    """
+    Implements a graph with 'N' vertices.  First, you connect the graph with
+    edges, which have a desired value associated.  Then the vertex values
+    are assigned, which will fail if the graph is cyclic.  The vertex values
+    are assigned such that the two values corresponding to an edge add up to
+    the desired edge value (mod N).
+    
+    Example:
+    >>> G = Graph(3)
+    >>> G.assign_vertex_values()
+    True
+    
+    Now we make an edge between vertex 0 and 1 with desired edge value 2:
+    >>> G.connect(0, 1, 2)
+    
+    Make another edge 1:2 with desired edge value 1:
+    >>> G.connect(1, 2, 1)
+    
+    The graph is still acyclic, and assigning values works:
+    >>> G.assign_vertex_values()
+    True
+    >>> G.vertex_values
+    [0, 2, 2]
+    
+    What do these values mean?
+    When you add the values for edge 0:1 you get 0 + 2 = 2, as desired.
+    For edge 1:2 you add 2 + 2 = 4 = 1 (mod 3), as desired.
+    
+    Adding edge 0:2 produces a loop, so the graph is no longer acyclic.
+    Assigning values fails.
+    >>> G.connect(0, 2, 0)
+    >>> G.assign_vertex_values()
+    False
+    """
+    def __init__(self, N):
+        self.N = N                     # number of vertices
+        
+        # maps a vertex number to the list of tuples (vertices, edge value)
+        # to which it is connected by edges.
+        self.adjacent = [[] for n in xrange(N)]
+    
+    def connect(self, vertex1, vertex2, edge_value):
+        """
+        Connect 'vertex1' and 'vertex2' with an edge, with associated
+        value 'value'
+        """
+        # Add vertices to each other's adjacent list
+        self.adjacent[vertex1].append( (vertex2, edge_value) )
+        self.adjacent[vertex2].append( (vertex1, edge_value) )
+        
+    def assign_vertex_values(self):
+        """
+        Try to assign the vertex values, such that, for each edge, you can
+        add the values for the two vertices involved and get the desired
+        value for that edge, i.e. the desired hash key.
+        This will fail when the graph is cyclic.
+
+        This is done by a Depth-First Search of the graph.  If the search
+        finds a vertex that was visited before, there's a loop and False is
+        returned immediately, i.e. the assignment is terminated.
+        On success (when the graph is acyclic) True is returned.
+        """
+        self.vertex_values = self.N * [-1]  # -1 means unassigned
+        
+        visited = self.N * [False]
+        
+        # Loop over all vertices, taking unvisited ones as roots.
+        for root in xrange(self.N):
+            if visited[root]:
+                continue
+
+            # explore tree starting at 'root'
+            self.vertex_values[root] = 0    # set arbitrarily to zero
+
+            # Stack of vertices to visit, a list of tuples (parent, vertex)
+            tovisit = [ (None, root) ]
+            while tovisit:
+                parent, vertex = tovisit.pop()
+                visited[vertex] = True
+                
+                # Loop over adjacent vertices, but skip the vertex we arrived
+                # here from the first time it is encountered.
+                skip = True
+                for neighbor, edge_value in self.adjacent[vertex]:
+                    if skip and neighbor == parent:
+                        skip = False
+                        continue
+                    
+                    if visited[neighbor]:
+                        # We visited here before, so the graph is cyclic.
+                        return False
+
+                    tovisit.append( (vertex, neighbor) )
+                    
+                    # Set new vertex's value to the desired edge value,
+                    # minus the value of the vertex we came here from.
+                    self.vertex_values[neighbor] = \
+                        ( edge_value - self.vertex_values[vertex] ) % self.N
+
+        # check if all vertices have a valid value
+        for vertex in xrange(self.N):
+            assert self.vertex_values[vertex] >= 0
+
+        # We got though, so the graph is acyclic,
+        # and all values are now assigned.
+        return True
+
+
+def generate_hash(kdic, Hash):
+    """
+    Return hash functions f1 and f2, and G for a perfect minimal hash.
+    Input is dictionary 'kdic' with the keys and desired hash values.
+    'Hash' is a random hash function generator, that means Hash(N) returns a
+    returns a random hash function which returns hash values from 0..N-1.
+    """
+    # N is the number of vertices in the graph G
+    N = 1 if not kdic else (max(kdic.values()) + 1)
+    if verbose >= 2:
+        sys.stderr.write('N = %i\n' % N)
+    
+    trail = 0 # Number of trial graphs so far
+    while True:
+        if (trail % trails) == 0:   # trails failures, increase N slightly
+            if trail > 0:
+                N = max(N+1, int(1.05*N))
+            if verbose:
+                sys.stderr.write('\n')
+                sys.stderr.write('Generating graphs N = %i ' % N)
+        trail += 1
+        
+        if verbose:
+            sys.stderr.write('.')
+            sys.stderr.flush()
+        
+        G = Graph(N)   # Create graph with N vertices
+        f1 = Hash(N)   # Create 2 random hash functions
+        f2 = Hash(N)
+        
+        # Connect vertices given by the values of the two hash functions
+        # for each key.  Associate the desired hash value with each edge.
+        for key, hashval in kdic.iteritems():
+            G.connect(f1(key), f2(key), hashval)
+        
+        # Try to assign the vertex values.  This will fail when the graph
+        # is cyclic.  But when the graph is acyclic it will succeed and we
+        # break out, because we're done.
+        if G.assign_vertex_values():
+            break
+    
+    if verbose:
+        sys.stderr.write('\nAcyclic graph found after %i trails.\n' % trail)
+        
+    if verbose >= 2:
+        sys.stderr.write('N = %i\n' % N)
+    if verbose:
+        sys.stderr.write('Checking generated hash function... ')
+
+    # Sanity check the result by actually verifying that all the keys
+    # hash to the right value.
+    for key, hashval in kdic.iteritems():
+        assert hashval == ( G.vertex_values[f1(key)] +
+                            G.vertex_values[f2(key)] ) % N
+    
+    if verbose:
+        sys.stderr.write('OK\n')
+    
+    return f1, f2, G.vertex_values
+
+
+class Hash1:
+    """
+    Random hash function generator.
+    For simplicity and speed, this doesn't implement any byte-level hashing
+    scheme.  Instead, a random string is generated and prefixing to str(key),
+    and then Python's hashing function is used.
+    """
+    def __init__(self, N):
+        self.N = N
+        self.salt = "".join(random.choice(string.letters + string.digits)
+                            for i in xrange(8))
+        
+    def __call__(self, key):
+        return hash(self.salt + str(key)) % self.N
+
+    template = """
+def perfect_hash(key):
+    return (G[ hash('$S1' + str(key)) % $NG ] +
+            G[ hash('$S2' + str(key)) % $NG ]) % $NG
+"""
+
+class Hash2:
+    """
+    Random hash function generator.
+    Simple byte level hashing, each byte is multiplied in sequence to a table
+    containing random numbers modulo N, and then these products are summed up.
+    The table with random numbers is dynamically expanded whenever
+    a key longer than the current table size is encountered.
+    """
+    def __init__(self, N):
+        self.N = N
+        self.salt = []
+        
+    def __call__(self, key):
+        skey = key
+        while len(self.salt) < len(skey): # add more salt if necessary
+            self.salt.append(random.randint(0, self.N-1))
+        
+        return sum(self.salt[i] * ord(c)
+                   for i, c in enumerate(skey)) % self.N
+    
+    template = """
+S1 = [$S1]
+S2 = [$S2]
+
+def hash_f(key, T):
+    return sum(T[i % $NS] * ord(c) for i, c in enumerate(str(key))) % $NG
+
+def perfect_hash(key):
+    return (G[hash_f(key, S1)] + G[hash_f(key, S2)]) % $NG
+"""
+
+
+class PerfHash:
+    """
+    This class is designed for creating perfect hash tables at run time,
+    which should be avoided, in particulat inserting new keys is
+    prohibitively expensive since a new perfect hash table needs to be
+    constructed.  However, this class can be usefull for testing.
+    
+    >>> d = PerfHash({'foo':(429, 'bar'), 42:True, False:'baz'})
+    >>> d['foo'], d[42], d[False]
+    ((429, 'bar'), True, 'baz')
+    >>> d[False] = (1, 2)
+    >>> d[False]
+    (1, 2)
+    >>> d.has_key('foo')
+    True
+    >>> d.has_key(True)
+    False
+    """
+    def __init__(self, dic):
+        self.klst = []
+        self.objs = []
+        kdic = {}
+        for hashval, (key, obj) in enumerate(dic.iteritems()):
+            self.klst.append(key)
+            self.objs.append(obj)
+            kdic[key] = hashval
+            
+        self.N = len(dic)
+        self.f1, self.f2, self.G = generate_hash(kdic, Hash1)
+
+    def __setitem__(self, newkey, newobj):
+        dic = {}
+        for key in self.klst:
+            dic[key] = self[key]
+        dic[newkey] = newobj
+        self.__init__(dic)
+
+    def hashval(self, key):
+        return ( self.G[self.f1(key)] + self.G[self.f2(key)] ) % len(self.G)
+    
+    def __getitem__(self, key):
+        h = self.hashval(key)
+        if h < self.N and key == self.klst[h]:
+            return self.objs[h]
+        else:
+            raise IndexError
+
+    def has_key(self, key):
+        h = self.hashval(key)
+        return h < self.N and key == self.klst[h]
+
+    
+class Format:
+    """
+    >>> class o:
+    ...     pass
+    >>> o.delimiter = ': '
+    >>> o.width = 75
+    >>> o.indent = 4
+    >>> x = Format( o )
+    >>> x( range(10) )
+    '0: 1: 2: 3: 4: 5: 6: 7: 8: 9'
+    >>> o.delimiter = '; '
+    >>> x = Format( o )
+    >>> x( range(5) )
+    '0; 1; 2; 3; 4'
+    >>> o.delimiter = ' '
+    >>> x = Format( o )
+    >>> x( range(5), quote = True )
+    '"0" "1" "2" "3" "4"'
+    >>> x(42)
+    '42'
+    >>> x('Hello')
+    'Hello'
+    """
+    def __init__(self, options):
+        names = ['width', 'indent', 'delimiter']
+        
+        for name in names:
+            setattr(self, name, getattr(options, name))
+
+        if verbose >=2:
+            sys.stderr.write("Format options:\n")
+            for name in names:
+                sys.stderr.write('  %s: %r\n' % (name, getattr(self, name)))
+    
+    def __call__(self, data, quote = False):
+        if type(data) != type([]):
+            return str(data)
+        
+        lendel = len(self.delimiter)
+        aux = StringIO.StringIO()
+        pos = 20
+        for i, elt in enumerate(data):
+            last = bool(i == len(data)-1)
+            
+            s = ('"%s"' if quote else '%s') % elt
+            
+            if pos + len(s) + lendel > self.width:
+                aux.write('\n' + (self.indent * ' '))
+                pos = self.indent
+            
+            aux.write(s)
+            pos += len(s)
+            if not last:
+                aux.write(self.delimiter)
+                pos += lendel
+
+        return aux.getvalue()
+
+
+def keyDict(keys_hashes):
+    """
+    Checks a list with (key, hashvalue) tupels and returns dictionary.
+
+    >>> d = keyDict([(1, 2), (3, 4), (5, 6)])
+    >>> d[3]
+    4
+    """
+    K = len(keys_hashes)     # number of keys
+    if verbose >= 2:
+        sys.stderr.write('K = %i\n' % K)
+        
+    kdic = dict(keys_hashes)
+    if len(kdic) < K:
+        sys.stderr.write('Warning: Input contains duplicate keys\n')
+    
+    if len(set(kdic.values())) < K:
+        sys.stderr.write('Warning: Input contains duplicate hash values\n')
+    
+    return kdic
+
+
+
+def generate_code(keys_hashes, template, Hash, options, extra_subs):
+    """
+    Takes a list of key value pairs and inserts the generated parameter
+    lists into the 'template' strinng.  'Hash' is the random hash function
+    generator, and the optional keywords are formating options.
+    The return value is the substituted code template.
+    """
+    f1, f2, G = generate_hash(keyDict(keys_hashes), Hash)
+    
+    assert f1.N == f2.N == len(G)
+    assert len(f1.salt) == len(f2.salt)
+    
+    fmt = Format(options)
+
+    return string.Template(template).substitute(
+        NS = len(f1.salt),
+        S1 = fmt(f1.salt),
+        S2 = fmt(f2.salt),
+        NG = len(G),
+        G  = fmt(G),
+        NK = len(keys_hashes),
+        K  = fmt([key for key, hashval in keys_hashes], quote = True),
+        H  = fmt([hashval for key, hashval in keys_hashes]),
+        **extra_subs)
+
+
+
+def read_table(filename, options):
+    """
+    Reads keys and desired hash value pairs from a file.  If no column
+    for the hash value is specified, a sequence of hash values is generated,
+    from 0 to N-1, where N is the number of rows found in the file.
+    """
+    if verbose >= 2:
+        sys.stderr.write("Reading table from file `%s' to extract keys.\n" %
+                         filename)
+    try:
+        f = file(filename)
+    except IOError :
+        exit("Error: Could not open `%s' for reading." % filename)
+
+    keys_hashes = []
+    hashval = -1
+
+    if verbose >= 2:
+        sys.stderr.write("Reader options:\n")
+        for name in ['comment', 'splitby', 'keycol', 'hashcol']:
+            sys.stderr.write('  %s: %r\n' %
+                             (name, getattr(options, name)))
+        
+    for n, line in enumerate(f):
+        line = line.strip()
+        if not line or line.startswith(options.comment):
+            continue
+
+        if line.count(options.comment): # strip content after comment
+            line = line.split(options.comment)[0].strip()
+
+        row = [col.strip() for col in line.split(options.splitby)]
+        
+        try:
+            key = row[options.keycol-1]
+        except IndexError :
+            exit("%s:%i: Error: Cannot read key, not enough columns." %
+                 (filename, n+1))
+            
+        if options.hashcol:
+            try:
+                val = row[options.hashcol-1]
+            except IndexError :
+                exit("%s:%i: Error: Cannot read hash value, not enough columns."
+                     % (filename, n+1))
+            try:
+                hashval = int(val)
+            except ValueError :
+                exit("%s:%i: Error: Cannot convert `%s' to int." %
+                     (filename, n+1, row[options.hashcol-1]))
+        else:
+            hashval += 1
+        
+        keys_hashes.append( (key, hashval) )
+
+    f.close()
+    
+    if not keys_hashes:
+        exit("Error: no keys found in file `%s'." % filename)
+
+    return keys_hashes
+
+
+
+def print_keys_hashes(keys_hashes):
+    fmt = '%-20s %10s'
+    head = fmt % ('Key', 'Hash value')
+    sys.stderr.write('\n' + head + '\n')
+    sys.stderr.write(len(head)*'-' + '\n')
+    for tup in keys_hashes:
+        sys.stderr.write(fmt % tup + '\n')
+    sys.stderr.write('\n')
+
+def read_template(filename):
+    if verbose >= 2:
+        sys.stderr.write("Reading template from file `%s'.\n" % filename)
+
+    try:
+        f = file(filename)
+    except IOError :
+        fatal_error("Error: Could not open `%s' for reading." % filename)
+
+    return f.read()
+
+
+def builtin_template(Hash):
+    return """\
+# =======================================================================
+# ================= Python code for perfect hash function ===============
+# =======================================================================
+
+G = [$G]
+""" + Hash.template + """
+# ============================ Sanity check =============================
+
+K = [$K]
+H = [$H]
+
+assert len(K) == len(H) == $NK
+
+for k, h in zip(K, H):
+    assert perfect_hash(k) == h
+"""
+
+
+def print_code(code, name, width = 78):
+    def center(s):
+        v = (width - len(s))/2
+        return '='*v + s + '='*v
+    sys.stderr.write(center(' BEGIN %s ' % name) + '\n')
+    sys.stderr.write(code + '\n')
+    sys.stderr.write(center(' END %s ' % name) + '\n')
+    
+
+def self_test(options):
+    import doctest
+    global verbose
+    print 'Starting self tests ...'
+
+    def random_word():
+        return ''.join(random.choice(string.letters + string.digits)
+                       for i in xrange(random.randint(1, 20)))
+
+    def flush_dot():
+        sys.stdout.write('.')
+        sys.stdout.flush()
+        
+    def run(K, Hash):
+        flush_dot()
+        
+        keys = [chr(65+i) for i in xrange(K)]
+        hashes = range(K)
+        
+        random.shuffle(keys)
+        random.shuffle(hashes)
+        
+        code = generate_code(zip(keys, hashes),
+                             builtin_template(Hash),
+                             Hash,
+                             options)
+        exec(code) in {}
+
+    verbose = False
+    for Hash in [Hash1, Hash2]:
+        for K in xrange(0, 27):
+            run(K, Hash)
+    print
+    
+    verbose = options.verbose
+    N = 250
+    for Hash in [Hash1, Hash2]:
+        if verbose:
+            print 'Generating approximately %i key/hash pairs ...' % N
+        kh = {}
+        for i in xrange(N):
+            kh[random_word()] = i
+
+        if verbose:
+            print 'Generating code for %i key/hash pairs ...' % len(kh)
+        code = generate_code(kh.items(),
+                             builtin_template(Hash),
+                             Hash,
+                             options)
+        if verbose:
+            print 'Executing code ...'
+        flush_dot()
+        exec(code) in {}
+
+    flush_dot()
+    d = PerfHash(dict([(100-i, i*i) for i in xrange(500)]))
+    for i in xrange(500):
+        assert d[100-i] == i*i
+    flush_dot()
+    d[None] = True
+    assert d[None] == True
+    
+    if verbose:
+        print 'Running doctest ...'
+    
+    verbose = False
+    failure_count, test_count = doctest.testmod(report = True, verbose = False)
+    print
+    if failure_count:
+        sys.stderr.write('FAILED\n')
+        sys.exit(2)
+    else:
+        sys.stderr.write('%i tests passed.\n' % test_count)
+        sys.stderr.write('OK\n')
+        sys.exit(0)
+
+
+if __name__ == '__main__':
+    from optparse import OptionParser
+    
+    usage = "usage: %prog [options] KEYS_FILE [TMPL_FILE]"
+    
+    description = """\
+Generates code for perfect hash functions from
+a file with keywords and a code template.
+If no template file is provided, a small built-in Python template
+is processed and the output code is written to stdout.
+"""
+    
+    parser = OptionParser(usage = usage,
+                          description = description,
+                          prog = sys.argv[0],
+                          version = "%prog 0.1")
+    
+    parser.add_option("--delimiter",
+                      action  = "store",
+                      default = ", ",
+                      help    = "Delimiter for list items used in output, "
+                                "the default delimiter is '%default'",
+                      metavar = "STR")
+
+    parser.add_option("--indent",
+                      action  = "store",
+                      default = 2,
+                      type    = "int",
+                      help    = "Make INT spaces at the beginning of a "
+                                "new line when generated list is wrapped. "
+                                "Default is %default",
+                      metavar = "INT")
+
+    parser.add_option("--width",
+                      action  = "store",
+                      default = 76,
+                      type    = "int",
+                      help    = "Maximal width of generated list when "
+                                "wrapped.  Default width is %default",
+                      metavar = "INT")
+
+    parser.add_option("--comment",
+                      action  = "store",
+                      default = "#",
+                      help    = "STR is the character, or sequence of "
+                                "characters, which marks the beginning "
+                                "of a comment (which runs till "
+                                "the end of the line), in the input "
+                                "KEYS_FILE. "
+                                "Default is '%default'",
+                      metavar = "STR")
+
+    parser.add_option("--splitby",
+                      action  = "store",
+                      default = ",",
+                      help    = "STR is the character by which the columns "
+                                "in the input KEYS_FILE are split. "
+                                "Default is '%default'",
+                      metavar = "STR")
+
+    parser.add_option("--keycol",
+                      action  = "store",
+                      default = 1,
+                      type    = "int",
+                      help    = "Specifies the column INT in the input "
+                                "KEYS_FILE which contains the keys. "
+                                "Default is %default, i.e. the first column.",
+                      metavar = "INT")
+                      
+    parser.add_option("--hashcol",
+                      action  = "store",
+                      default = 0,
+                      type    = "int",
+                      help    = "Specifies the column INT in the input "
+                                "KEYS_FILE which contains the desired "
+                                "hash values. "
+                                "By default the hash values are given by the "
+                                "sequence 0..N-1.",
+                      metavar = "INT")
+                      
+    parser.add_option("--trails",
+                      action  = "store",
+                      default = 5,
+                      type    = "int",
+                      help    = "Specifies the number of trails before "
+                                "N is increased.  A small INT will give "
+                                "compute faster, but the array G will be "
+                                "large.  A large INT will take longer to "
+                                "compute but G will be smaller. "
+                                "Default is %default",
+                      metavar = "INT")
+                      
+    parser.add_option("--hft",
+                      action  = "store",
+                      default = 2,
+                      type    = "int",
+                      help    = "Hash function type INT (see documentation), "
+                                "The default is %default",
+                      metavar = "INT")
+
+    parser.add_option("-e", "--execute",
+                      action  = "store_true",
+                      help    = "Execute the generated code within "
+                                "the Python interpreter.")
+    
+    parser.add_option("-o", "--output",
+                      action  = "store",
+                      help    = "Specify output FILE explicitly. "
+                                "`-o std' means standard output. "
+                                "`-o no' means no output. "
+                                "By default, the file name is obtained "
+                                "from the name of the template file by "
+                                "substituting `tmpl' to `code'.",
+                      metavar = "FILE")
+    
+    parser.add_option("--test",
+                      action  = "store_true",
+                      help    = "Perform self test")
+    
+    parser.add_option("-v", "--verbose",
+                      action  = "count",
+                      help    = "Be verbose, "
+                                "use -vv to be even more verbose")
+    
+    options, args = parser.parse_args()
+    print type(options), '\n', repr(options)
+
+    if options.trails > 0:
+        trails = options.trails
+    else:
+        parser.error("trails before increasing N has to be larger than zero")
+
+    verbose = options.verbose
+    
+    if options.test:
+        self_test(options)
+    
+    if len(args) not in (1, 2):
+        parser.error("incorrect number of arguments")
+
+    if len(args) == 2 and not args[1].count('tmpl'):
+        parser.error("template filename does not contain 'tmpl'")
+
+    if options.hft == 1:
+        Hash = Hash1
+    elif options.hft == 2:
+        Hash = Hash2
+    else:
+        parser.error("Hash function %i not implemented.")
+    
+    # --------------------- end parsing and checking --------------
+    
+    # ---------------- keys_file
+    
+    keys_file = args[0]
+    
+    if verbose:
+        sys.stderr.write("keys_file = %r\n" % keys_file)
+    
+    # ---------------- keys_hashes
+    
+    keys_hashes = read_table(keys_file, options)
+    
+    if verbose >= 3:
+        print_keys_hashes(keys_hashes)
+        
+    # ---------------- tmpl_file
+
+    if len(args) == 2:
+        tmpl_file = args[1]
+    else:
+        tmpl_file = None
+    
+    if verbose:
+        sys.stderr.write("tmpl_file = %r\n" % tmpl_file)
+
+    # ---------------- template
+
+    if tmpl_file:
+        template = read_template(tmpl_file)
+    else:
+        template = builtin_template(Hash)
+    
+    if verbose >= 3:
+        print_code(template, 'TEMPLATE')
+    
+    # ---------------- outname
+    
+    if options.output:
+        outname = options.output
+        
+    else:
+        if tmpl_file:
+            if tmpl_file.count('tmpl'):
+                outname = tmpl_file.replace('tmpl', 'code')
+            else:
+                exit("Hmm, template filename does not contain 'tmpl'")
+        else:
+            outname = 'std'
+    
+    if verbose:
+        sys.stderr.write("outname = %r\n" % outname)
+
+    # ---------------- outstream
+    
+    if outname == 'std':
+        outstream = sys.stdout
+
+    elif outname == 'no':
+        outstream = None
+        
+    else:
+        try:
+            outstream = open(outname, 'w')
+        except IOError :
+            exit("Error: Could not open `%s' for writing." % outname)
+
+    # ---------------- generated code
+    
+    code = generate_code(keys_hashes, template, Hash, options)
+    if verbose >= 3:
+        print_code(code, 'GENERATED CODE')
+
+    # ---------------- execute code
+    
+    if options.execute or template == builtin_template(Hash):
+        if verbose:
+            sys.stderr.write('Executing code...\n')
+        exec(code)
+
+    # ---------------- write code to output stream
+
+    if outstream:
+        outstream.write(code)
+        if not outname == 'std':
+            outstream.close()

+ 32 - 0
components/rtgui/utils/perfect_hash/run

@@ -0,0 +1,32 @@
+#!/bin/bash
+
+function showpwd ()
+{
+    echo '=============' `pwd`
+}
+
+# perform programs self test
+showpwd
+./perfect_hash.py --test || exit 1
+
+# update documentation
+for folder in doc
+do
+  cd $folder
+  showpwd
+  make
+  cd ..
+done
+
+# run examples
+for folder in example* graph
+do
+  cd $folder
+  showpwd
+  make       || exit 1
+  make test  || exit 1
+  make clean
+  cd ..
+done
+
+rm perfect_hash.pyc

+ 163 - 0
components/rtgui/utils/stract_cjk.py

@@ -0,0 +1,163 @@
+#encoding: utf-8
+from perfect_hash import perfect_hash
+
+import re, string, os, random
+
+cur_dir = os.path.abspath(os.path.dirname(__file__))
+
+unicode_chinese_re = u'[\u2E80-\u2EFF\u2F00-\u2FDF\u3000-\u303F\u31C0-\u31EF\u3200-\u32FF\u3300-\u33FF\u3400-\u4DBF\u4DC0-\u4DFF\u4E00-\u9FBF\uF900-\uFAFF\uFE30-\uFE4F\uFF00-\uFFEF]'
+match_re = re.compile(unicode_chinese_re)
+
+def _get_font_lib(f):
+    reading_data = False
+    data = []
+    for i in f.readlines():
+        if i.strip() == 'FONT_BMP_DATA_BEGIN':
+            reading_data = True
+            continue
+        if i.strip() == 'FONT_BMP_DATA_END':
+            break
+        if reading_data:
+            line = [k for k in i.strip().split(',') if k]
+            data.extend([int(k, 16) for k in line])
+    return data
+
+class font_lib(object):
+    def __init__(self, f, width, height, encoding):
+        self.width = width
+        self.height = height
+        self._lib = _get_font_lib(f)
+        # byte per charactor
+        self._bpc = (width+7)//8*height
+        self.encoding = encoding
+        self._finished_push = False
+
+        self.char_dict = {}
+
+    def get_char_data(self, char):
+        #char_gb = char.encode(self.encoding)
+
+        # copied from font_hz_bmp.c
+        sec, idx = [ord(i) - 0xA0 for i in char]
+        #print 'sec %d, idx %d for' % (sec, idx), char
+        start = (94 * (sec-1) + (idx-1)) * self._bpc
+        return self._lib[start:start+self._bpc]
+
+    def push_char(self, c):
+        self.char_dict[c] = self.char_dict.get(c, 0) + 1
+
+    def push_file(self, f):
+        try:
+            for i in f:
+                t = re.findall(match_re, unicode(i.decode(self.encoding)))
+                if t:
+                    for c in t:
+                        self.push_char(c.encode(self.encoding))
+        except UnicodeDecodeError as e:
+            try:
+                print 'error in decoding %s' % f.name
+            except:
+                print 'error in decoding string %s' % f
+            # re-raise the exception and terminate the building process
+            raise
+
+    def _finish_push(self):
+        if self._finished_push:
+            return
+
+        self._char_li = zip(self.char_dict.keys(), self.char_dict.values())
+        self._char_li.sort(key=lambda x:x[1], reverse=True)
+        self._finished_push = True
+
+        #for i in self._char_li:
+            #print i[0], i[1]
+
+    def get_hash_map(self):
+        self._finish_push()
+        li = []
+        for  i, k in enumerate(self._char_li):
+            li.append((k[0], i))
+        return li
+
+    def get_new_font_lib(self):
+        self._finish_push()
+        dat = []
+        for c, f in self._char_li:
+            dat.extend(self.get_char_data(c))
+        return dat
+
+    def finish(self):
+        return self.get_hash_map(), self.get_new_font_lib()
+
+class mph_options(object):
+    'mock object for options'
+    def __init__(self, verbose=4, delimiter=', ', indent=4, width=80):
+        self.verbose = verbose
+        self.delimiter = delimiter
+        self.indent = indent
+        self.width = width
+
+def gen_char_mph(font_lib):
+    template = open(os.path.join(cur_dir, '..', 'common', 'font_mph-tmpl.c'), 'r').read()
+    opt = mph_options()
+    hmap, flib = font_lib.finish()
+    #print 'compact font lib: %d chars included.' % len(hmap)
+    #for i in hmap:
+        #print i[0], repr(i[0]), i[1]
+    code = perfect_hash.generate_code(hmap, template, perfect_hash.Hash2, opt,
+            extra_subs={
+                'width':str(font_lib.width),
+                'height':str(font_lib.height),
+                'font_data':', '.join([hex(i) for i in flib])})
+
+    return code
+
+# {name:[file_name, height, width, encoding, instance]}
+_font_map = {'hz16':{'fname':'common/hz16font.c',
+                     'height':16,
+                     'width':16,
+                     'encoding':'GB2312',
+                     'flib':None},
+             'hz12':{'fname':'common/hz12font.c',
+                     'height':12,
+                     'width':12,
+                     'encoding':'GB2312',
+                     'flib':None}
+            }
+
+def get_font_lib(name):
+    if name not in _font_map.keys():
+        return None
+
+    if _font_map[name]['flib'] is None:
+        _font_map[name]['flib'] = font_lib(open(
+                                       os.path.join(cur_dir, '..', _font_map[name]['fname']), 'r'),
+                                       _font_map[name]['height'],
+                                       _font_map[name]['width'],
+                                       _font_map[name]['encoding'])
+    return _font_map[name]['flib']
+
+def gen_cmp_font_file():
+    for i in _font_map:
+        fl = _font_map[i]['flib']
+        if fl is not None:
+            code = gen_char_mph(fl)
+            with open(os.path.join(cur_dir, '..', 'common', 'font_cmp_%s.c' % i), 'w') as f:
+                f.write(code)
+
+if __name__ == '__main__':
+    import sys
+
+    lib = get_font_lib('hz16')
+    libn = get_font_lib('hz16')
+    assert(lib is libn)
+
+    lib.push_file(open(sys.argv[1], 'rb'))
+
+    hmap, flib = lib.finish()
+    for i in hmap:
+        print i[0], i[1]
+
+    assert(len(flib) == 32 * len(hmap))
+
+    print gen_char_mph(lib)

+ 6 - 6
components/rtgui/widgets/box.c

@@ -73,7 +73,7 @@ static void rtgui_box_layout_vertical(struct rtgui_box *box, struct rtgui_rect *
     {
         rtgui_widget_t *widget = rtgui_list_entry(node, struct rtgui_widget, sibling);
         if (widget->align & RTGUI_ALIGN_STRETCH) space_count ++;
-        else total_height += widget->mini_height;
+        else total_height += widget->min_height;
     }
 
     /* calculate the height for each spaces */
@@ -98,8 +98,8 @@ static void rtgui_box_layout_vertical(struct rtgui_box *box, struct rtgui_rect *
 
         /* reset rect */
         rtgui_rect_moveto(rect, -rect->x1, -rect->y1);
-        rect->x2 = widget->mini_width;
-        rect->y2 = widget->mini_height;
+        rect->x2 = widget->min_width;
+        rect->y2 = widget->min_height;
 
         /* left in default */
         rtgui_rect_moveto(rect, next_x, next_y);
@@ -166,7 +166,7 @@ static void rtgui_box_layout_horizontal(struct rtgui_box *box, struct rtgui_rect
     {
         rtgui_widget_t *widget = rtgui_list_entry(node, struct rtgui_widget, sibling);
         if (widget->align & RTGUI_ALIGN_STRETCH) space_count ++;
-        else total_width += widget->mini_width;
+        else total_width += widget->min_width;
     }
 
     if (space_count != 0)
@@ -191,8 +191,8 @@ static void rtgui_box_layout_horizontal(struct rtgui_box *box, struct rtgui_rect
 
         /* reset rect */
         rtgui_rect_moveto(rect, -rect->x1, -rect->y1);
-        rect->x2 = widget->mini_width;
-        rect->y2 = widget->mini_height;
+        rect->x2 = widget->min_width;
+        rect->y2 = widget->min_height;
 
         /* top in default */
         rtgui_rect_moveto(rect, next_x, next_y);

+ 9 - 5
components/rtgui/widgets/button.c

@@ -104,7 +104,8 @@ rt_bool_t rtgui_button_event_handler(struct rtgui_object *object, struct rtgui_e
     break;
 
     case RTGUI_EVENT_MOUSE_BUTTON:
-        if (RTGUI_WIDGET_IS_HIDE(widget)) return RT_FALSE;
+        if (RTGUI_WIDGET_IS_HIDE(widget))
+            return RT_FALSE;
         {
             struct rtgui_event_mouse *emouse = (struct rtgui_event_mouse *)event;
 
@@ -159,9 +160,6 @@ rt_bool_t rtgui_button_event_handler(struct rtgui_object *object, struct rtgui_e
                     /* need callback */
                     rt_bool_t need_cb = RT_FALSE;
 
-                    win = RTGUI_WIN(RTGUI_WIDGET(btn)->toplevel);
-                    win->last_mevent_widget = RTGUI_WIDGET(btn);
-
                     /* we need to decide whether the callback will be invoked
                      * before the flag has changed. Moreover, we cannot invoke
                      * it directly here, because the button might be destroyed
@@ -174,14 +172,20 @@ rt_bool_t rtgui_button_event_handler(struct rtgui_object *object, struct rtgui_e
                         need_cb = RT_TRUE;
                     }
 
-                    /* it's a normal button */
+                    /* if the button will handle the mouse up event here, it
+                     * should not be the last_mevent_widget. Take care that
+                     * don't overwrite other widgets. */
+                    win = RTGUI_WIN(RTGUI_WIDGET(btn)->toplevel);
                     if (emouse->button & RTGUI_MOUSE_BUTTON_DOWN)
                     {
                         btn->flag |= RTGUI_BUTTON_FLAG_PRESS;
+                        win->last_mevent_widget = RTGUI_WIDGET(btn);
                     }
                     else
                     {
                         btn->flag &= ~RTGUI_BUTTON_FLAG_PRESS;
+                        if (win->last_mevent_widget == RTGUI_WIDGET(btn))
+                            win->last_mevent_widget = RT_NULL;
                     }
 
                     /* draw button */

+ 4 - 4
components/rtgui/widgets/combobox.c

@@ -48,7 +48,7 @@ rt_bool_t rtgui_combobox_pdwin_onitem(struct rtgui_object *object, struct rtgui_
     if (combo->on_selected != RT_NULL)
         combo->on_selected(RTGUI_OBJECT(combo), RT_NULL);
 
-    rtgui_win_hiden(pd_win);
+    rtgui_win_hide(pd_win);
     rtgui_widget_update(RTGUI_WIDGET(combo));
 
     return RT_FALSE;
@@ -56,7 +56,7 @@ rt_bool_t rtgui_combobox_pdwin_onitem(struct rtgui_object *object, struct rtgui_
 
 rt_bool_t rtgui_combobox_pdwin_ondeactive(struct rtgui_object *object, struct rtgui_event *event)
 {
-    rtgui_win_hiden(RTGUI_WIN(object));
+    rtgui_win_hide(RTGUI_WIN(object));
     return RT_TRUE;
 }
 
@@ -226,7 +226,7 @@ rt_bool_t rtgui_combobox_event_handler(struct rtgui_object *object, struct rtgui
         if (focused->widget != RT_NULL)
         {
             /* hide pull down window */
-            rtgui_win_hiden(RTGUI_WIN(box->pd_win));
+            rtgui_win_hide(RTGUI_WIN(box->pd_win));
             rtgui_combobox_ondraw(box);
         }
     }
@@ -255,7 +255,7 @@ static rt_bool_t rtgui_combobox_pulldown_hide(struct rtgui_object *object, struc
     if (box == RT_NULL) return RT_TRUE;
 
     /* hide pull down window */
-    rtgui_win_hiden(RTGUI_WIN(box->pd_win));
+    rtgui_win_hide(RTGUI_WIN(box->pd_win));
 
     /* clear pull down button state */
     box->pd_pressed = RT_FALSE;

+ 309 - 0
components/rtgui/widgets/digfont.c

@@ -0,0 +1,309 @@
+/*
+ * File      : digfont.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2012-12-21     pife         first version
+ */
+
+#include <rtthread.h>
+#include <rtgui/rtgui.h>
+#include <rtgui/dc.h>
+#include <rtgui/widgets/digfont.h>
+
+#define DIGFONT_V  1
+#define DIGFONT_H  0
+
+int rtgui_digitfont_create(struct rtgui_digitfont * font)
+{
+    int i;
+    int half;
+    int space;
+    int seg35_y;
+    int hight;
+    struct rtgui_digitfont_data * data, *databuf;
+    struct rtgui_digitfont_data temp, temp2;;
+
+    data= rt_malloc(sizeof(struct rtgui_digitfont_data) * 7 * font->seg1_nr);
+    if (data== RT_NULL)
+    {
+        rt_kprintf("out of memory.\n");
+        goto __err;
+    }
+    databuf = font->data = data;
+
+    data = &temp;
+    half = font->seg1_nr >> 1;
+    space = font->seg1_hspace;
+    seg35_y = font->seg1_vspace + font->seg2_len + (half<<1) - font->seg1_vspace;
+    hight = (font->seg1_vspace << 1) + font->seg2_len + font->seg3_len + (half << 1) - 1;
+
+    //seg 1
+    data->type = DIGFONT_H;
+    data->x =  font->seg1_hspace;
+    data->y = 0;
+    data->len = font->seg1_len;
+
+    *databuf++ = *data;
+    for(i=1; i<font->seg1_nr; i++)
+    {
+        data->len -= 2;
+        data->x ++;
+        data->y ++;
+        *databuf++ = *data;
+    }
+
+    //seg 2
+    data->type = DIGFONT_V;
+    data->x =  (font->seg1_hspace << 1) + font->seg1_len -1;
+    data->y = font->seg1_vspace ;
+    data->len = font->seg2_len;
+    *databuf++ = *data;
+    for(i=1; i<font->seg1_nr; i++)
+    {
+        if (i >= half)
+        {
+            data->len -=  2;
+        }
+        data->x --;
+        data->y ++;
+        *databuf++ = *data;
+    }
+
+    //seg 3
+    data->type = DIGFONT_V;
+    data->x =  (font->seg1_hspace << 1) + font->seg1_len -1;
+    data->y = seg35_y;
+    data->len = font->seg3_len;
+    *databuf++ = *data;
+    temp2 = *data;
+    for(i=1; i<font->seg1_nr; i++)
+    {
+        if (i < half)
+            data->y --;
+        else
+        {
+            data->len -=  2;
+            data->y ++;
+        }
+
+        data->x --;
+        *databuf++ = *data;
+    }
+
+    // seg4
+    data->type = DIGFONT_H;
+    data->x =  font->seg1_hspace;
+    data->y = hight -1;
+    data->len = font->seg1_len;
+    *databuf++ = *data;
+    for(i=1; i<font->seg1_nr; i++)
+    {
+        data->len -= 2;
+        data->x ++;
+        data->y --;
+        *databuf++ = *data;
+    }
+
+    //seg5
+    data->type = DIGFONT_V;
+    data->x = 0;
+    data->y = seg35_y;
+    data->len = font->seg3_len;
+    *databuf++ = *data;
+
+    for(i=1; i<font->seg1_nr; i++)
+    {
+        if (i < half)
+            data->y --;
+        else
+        {
+            data->len -=  2;
+            data->y ++;
+        }
+
+        data->x ++;
+        *databuf++ = *data;
+    }
+
+    //seg 6
+    data->type = DIGFONT_V;
+    data->x = 0;
+    data->y = font->seg1_vspace ;
+    data->len = font->seg2_len;
+    *databuf++ = *data;
+    for(i=1; i<font->seg1_nr; i++)
+    {
+        if (i >= half)
+        {
+            data->len -=  2;
+        }
+        data->x ++;
+        data->y ++;
+        *databuf++ = *data;
+    }
+
+    //seg7
+    data->type = DIGFONT_H;
+    data->x = font->seg1_hspace + half - 1;
+    data->y = font->seg1_vspace + font->seg2_len + half -1;
+    data->len = (font->seg1_hspace << 1) + font->seg1_len - \
+                ((font->seg1_hspace + half -1) << 1);
+    *databuf++ = *data;
+    temp2 = *data;
+    for(i=0; i<half; i++)
+    {
+        data->x ++;
+        data->y --;
+        data->len -=  2;
+        *databuf++ = *data;
+    }
+
+    *data = temp2;
+    for (i=0; i<half; i++)
+    {
+        data->x ++;
+        data->y ++;
+        data->len -=  2;
+        *databuf++ = *data;
+    }
+
+    return 0;
+
+__err:
+    return -1;
+}
+
+int rtgui_dc_draw_digitfont(struct rtgui_dc *dc, struct rtgui_digitfont * font, rtgui_rect_t * rect)
+{
+    int i, size;
+    struct rtgui_digitfont_data * data;
+
+    size = font->seg1_nr * 7;
+    data = font->data;
+
+    for(i=0; i<size; i++)
+    {
+        if (data->type == DIGFONT_H)
+            rtgui_dc_draw_hline(dc, rect->x1 + data->x, \
+                                rect->x1 + data->x + data->len, rect->y1 + data->y);
+        else
+            rtgui_dc_draw_vline(dc, rect->x1 + data->x, rect->y1 + data->y, \
+                                rect->y1 + data->y + data->len);
+
+        data++;
+    }
+}
+
+const char digtube_code_table[] =
+{ 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,};
+
+int rtgui_dc_draw_digitfont_code(struct rtgui_dc *dc, struct rtgui_digitfont * font, rtgui_rect_t * rect, char code)
+{
+	int i,j;
+	struct rtgui_digitfont_data * data;
+	rtgui_color_t color;
+
+	data = font->data;
+	
+	color = RTGUI_DC_FC(dc);
+	for(i=0; i<7; i++)
+	{
+		if (code & (1 << i))
+			RTGUI_DC_FC(dc) = color;
+		else
+			RTGUI_DC_FC(dc) = RTGUI_DC_BC(dc);
+
+		for (j=0; j<font->seg1_nr; j++)
+		{
+			if (data->type == DIGFONT_H)
+				rtgui_dc_draw_hline(dc, rect->x1 + data->x, \
+				rect->x1 + data->x + data->len, rect->y1 + data->y);
+			else
+				rtgui_dc_draw_vline(dc, rect->x1 + data->x, rect->y1 + data->y, \
+				rect->y1 + data->y + data->len);
+
+			data++;
+		}	
+	}
+	RTGUI_DC_FC(dc) = color;
+
+	return 0;
+}
+
+int rtgui_get_digfont_metrics(struct rtgui_digitfont * font, rtgui_rect_t * rect) 
+{
+	int half = font->seg1_nr >> 1;
+	rect->x1 = 0;
+	rect->y1 = 0;
+	rect->x2 = (font->seg1_hspace << 1) + font->seg1_len;
+	rect->y2 = (font->seg1_vspace << 1) + font->seg2_len + font->seg3_len + (half << 1) - 1;
+	return 0;
+}
+
+/* debug */
+struct rtgui_digitfont digitfont_40 =
+{
+	34,  //int seg1_len;
+	3,   //int seg1_hspace;
+	1,   //int seg1_vpace;
+	9,   //int seg1_nr; //9
+	30,  //int seg2_len;
+	30,  //int seg3_len;
+	RT_NULL,
+};
+
+#ifdef _WIN32
+#include  <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+static char fontbuf[80];
+int digfont_file(char * name, struct rtgui_digitfont * font)
+{
+    int i;
+    int size;
+    FILE * file;
+    struct rtgui_digitfont_data * data;
+
+    if (font->data == RT_NULL)
+        rtgui_digitfont_create(font);
+
+    /* create a file to store data */
+    file = fopen(name, "wb + ");
+    if (file == RT_NULL)
+    {
+        rt_kprintf("open < % s > failed.\n", name);
+        return -1;
+    }
+    data = font->data;
+    size = font->seg1_nr * 7;
+
+    for( i=0; i<size; i++)
+    {
+        if ((i % (font->seg1_nr)) == 0)
+        {
+            sprintf(fontbuf, "\n/* seg <%d> */\n", i/font->seg1_nr + 1);
+            fwrite(fontbuf, strlen(fontbuf), 1, file);
+        }
+
+        sprintf(fontbuf, " { % 2d, % 2d, % 2d, % 2d}, \n", data->x, data->y, data->len, data->type);
+        fwrite(fontbuf, strlen(fontbuf), 1, file);
+        data ++;
+    }
+    fclose(file);
+
+    return 0;
+}
+#if defined(RT_USING_FINSH)
+#include <finsh.h>
+FINSH_FUNCTION_EXPORT(digfont_file, create the font file of digit font)
+#endif
+
+#endif

+ 174 - 0
components/rtgui/widgets/digtube.c

@@ -0,0 +1,174 @@
+/*
+ * File      : digfont.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2012-12-21     pife         first version
+ */
+
+#include <rtgui/dc.h>
+#include <rtgui/widgets/digtube.h>
+
+static void _rtgui_digtube_constructor(struct rtgui_digtube * digtube)
+{
+    RTGUI_WIDGET_TEXTALIGN(digtube) = RTGUI_ALIGN_CENTER;
+
+	/* init widget and set event handler */
+	rtgui_object_set_event_handler(RTGUI_OBJECT(digtube), rtgui_digtube_event_handler);
+}
+
+static void _rtgui_digtube_destructor(struct rtgui_digtube *digtube)
+{
+#ifndef RTGUI_DIGTUBE_USE_CONST_FONT
+	/* release font memory */
+	rt_free(digtube->digitfont.data);
+	digtube->digitfont.data = RT_NULL;
+#endif
+}
+
+DEFINE_CLASS_TYPE(digtube, "digtube",
+				  RTGUI_WIDGET_TYPE,
+				  _rtgui_digtube_constructor,
+				  _rtgui_digtube_destructor,
+				  sizeof(struct rtgui_digtube));
+
+rt_bool_t rtgui_digtube_event_handler(struct rtgui_object *object, struct rtgui_event *event)
+{
+	struct rtgui_digtube *digtube;
+    struct rtgui_dc *dc;
+    rtgui_rect_t rect;
+    rtgui_rect_t text_rect;
+	rtgui_color_t color;
+	char * disbuf;
+	char tempbuf[8];
+	int i;
+
+	RTGUI_WIDGET_EVENT_HANDLER_PREPARE
+
+	digtube = RTGUI_DIGTUBE(object);
+	switch (event->type)
+	{
+	case RTGUI_EVENT_PAINT:
+
+	    dc = rtgui_dc_begin_drawing(RTGUI_WIDGET(object));
+		if (dc == RT_NULL)
+			break;
+		rtgui_widget_get_rect(RTGUI_WIDGET(object), &rect);
+		rtgui_dc_fill_rect(dc, &rect);
+
+		if (! (digtube->tube_style & RTGUI_DIGTUBE_STYLE_NOBACKFONT))
+		{
+			color = RTGUI_DC_BC(dc);
+			RTGUI_DC_BC(dc) = digtube->digit_bc;
+		}
+		
+		if (digtube->tube_style & RTGUI_DIGTUBE_STYLE_DISCODES)
+			disbuf = (char *) (digtube->value);
+		else
+		{
+			const char * format =  
+				digtube->tube_style & RTGUI_DIGTUBE_STYLE_DISHEXNUM ? 
+				"%7x" : "%7d";
+
+			disbuf = &tempbuf[0];
+			rt_snprintf(disbuf, 8, format, digtube->value);
+			
+			/* */
+			for (i=0; i<7; i++)
+			{
+				if (disbuf[i] == ' ')
+					disbuf[i] = 0;
+				else
+				{
+					disbuf[i] = (disbuf[i] >= '0' && disbuf[i] <= '9') ? disbuf[i] - '0':
+						disbuf[i] - 'a' + 10;
+
+					disbuf[i] = digtube_code_table[disbuf[i]];
+				}
+			}
+
+			disbuf = tempbuf + 7 - digtube->tube_count;
+		}
+
+		text_rect.x1 = 0;
+		text_rect.y1 = 0;
+		text_rect.x2 = (digtube->digit_width + digtube->digit_space) * digtube->tube_count
+		                -digtube->digit_space;
+		text_rect.y2 = digtube->digit_hight;
+
+		rtgui_rect_moveto_align(&rect, &text_rect, RTGUI_DC_TEXTALIGN(dc));
+		for (i=0; i<digtube->tube_count; i++)
+		{
+			rtgui_dc_draw_digitfont_code(dc, &digtube->digitfont, &text_rect, disbuf[i]);
+			text_rect.x1 += digtube->digit_width + digtube->digit_space;
+		}
+
+		if (! (digtube->tube_style & RTGUI_DIGTUBE_STYLE_NOBACKFONT))
+			RTGUI_DC_BC(dc) = color;
+		rtgui_dc_end_drawing(dc);
+		break;
+	default:
+		return rtgui_widget_event_handler(object, event);
+	}
+
+	return RT_FALSE;
+}
+
+rtgui_digtube_t *rtgui_digtube_create(
+	struct rtgui_digitfont * digitfont, 
+	int count, 
+	void * value, 
+	int style)
+{
+	struct rtgui_digtube *digtube;
+	rtgui_rect_t rect;
+
+	RT_ASSERT(count <= 7 && count > 0)
+
+	digtube = (struct rtgui_digtube *) rtgui_widget_create(RTGUI_DIGTUBE_TYPE);
+	if (digtube == RT_NULL)
+		return RT_NULL;
+
+	/* set field */
+	if (digitfont == RT_NULL)
+		digitfont = &digitfont_40;
+
+	rt_memcpy(& digtube->digitfont, digitfont, sizeof(struct rtgui_digitfont));
+
+#ifndef RTGUI_DIGTUBE_USE_CONST_FONT
+	if (digtube->digitfont.data == RT_NULL)
+		rtgui_digitfont_create(& digtube->digitfont);
+#endif
+
+	/* set default rect */
+	rtgui_get_digfont_metrics(&digtube->digitfont, &rect);
+	digtube->digit_width = rect.x2;
+	digtube->digit_hight = rect.y2;
+	digtube->tube_count = count;
+	digtube->digit_space = RTGUI_DIGTUBE_DEFAULT_SPACE;
+
+	rect.x2 = (rect.x2 + digtube->digit_space) * count - digtube->digit_space;
+	rect.y2 = rect.y2;
+
+	RTGUI_WIDGET_BACKGROUND(digtube) = rtgui_theme_default_bc();
+	RTGUI_WIDGET_FOREGROUND(digtube) = RTGUI_DIGTUBE_DEFAULT_FC;
+	rtgui_widget_set_rect(RTGUI_WIDGET(digtube), &rect);
+
+	/* set display value */
+	digtube->digit_bc = RTGUI_DIGTUBE_DEFAULT_DIGIT_BC;
+	digtube->value = value;
+	digtube->tube_style = style;
+	
+	return digtube;
+}
+
+void rtgui_digtube_destroy(rtgui_digtube_t *digtube)
+{
+    rtgui_widget_destroy(RTGUI_WIDGET(digtube));
+}

+ 1 - 1
components/rtgui/widgets/filelist_view.c

@@ -250,7 +250,7 @@ static rt_bool_t rtgui_filelist_view_on_folder_item(rtgui_object_t *object, stru
     view = RTGUI_FILELIST_VIEW(menu->user_data);
 
     /* hide window */
-    rtgui_win_hiden(menu);
+    rtgui_win_hide(menu);
 
     switch (listbox->current_item)
     {

+ 7 - 7
components/rtgui/widgets/menu.c

@@ -61,7 +61,7 @@ static rt_bool_t _rtgui_menu_onitem(struct rtgui_object *object, struct rtgui_ev
                 if (!RTGUI_WIDGET_IS_HIDE(menu->sub_menu))
                 {
                     /* hide this sub menu */
-                    rtgui_win_hiden(RTGUI_WIN(menu->sub_menu));
+                    rtgui_win_hide(RTGUI_WIN(menu->sub_menu));
                     return RT_FALSE;
                 }
 
@@ -91,9 +91,9 @@ static rt_bool_t _rtgui_menu_onitem(struct rtgui_object *object, struct rtgui_ev
         /* hide sub-menu */
         if (menu->sub_menu != RT_NULL)
         {
-            rtgui_menu_hiden(menu->sub_menu);
+            rtgui_menu_hide(menu->sub_menu);
         }
-        rtgui_menu_hiden(menu);
+        rtgui_menu_hide(menu);
     }
     return RT_FALSE;
 }
@@ -183,7 +183,7 @@ static rt_bool_t rtgui_menu_on_deactivate(struct rtgui_object *object, rtgui_eve
             return RT_TRUE;
     }
 
-    rtgui_win_hiden(RTGUI_WIN(menu));
+    rtgui_win_hide(RTGUI_WIN(menu));
     if (menu->on_menuhide != RT_NULL)
     {
         menu->on_menuhide(RTGUI_OBJECT(menu), RT_NULL);
@@ -282,13 +282,13 @@ void rtgui_menu_pop(struct rtgui_menu *menu, int x, int y)
     rtgui_win_show(RTGUI_WIN(menu), RT_FALSE);
 }
 
-void rtgui_menu_hiden(struct rtgui_menu *menu)
+void rtgui_menu_hide(struct rtgui_menu *menu)
 {
-    rtgui_win_hiden(RTGUI_WIN(menu));
+    rtgui_win_hide(RTGUI_WIN(menu));
     /* un-select item */
     menu->items_list->current_item = -1;
 
     if (menu->parent_menu != RT_NULL)
-        rtgui_menu_hiden(menu->parent_menu);
+        rtgui_menu_hide(menu->parent_menu);
 }
 

+ 2 - 1
components/rtgui/widgets/notebook.c

@@ -539,7 +539,8 @@ void rtgui_notebook_set_current_by_index(struct rtgui_notebook *notebook, rt_uin
         widget = notebook->childs[notebook->current].widget;
         rtgui_widget_show(widget);
         rtgui_widget_update_clip(widget);
-        rtgui_widget_update(widget);
+        /* the whole notebook need an update */
+        rtgui_widget_update(RTGUI_WIDGET(notebook));
         rtgui_widget_focus(widget);
     }
 }

+ 4 - 4
components/rtgui/widgets/radiobox.c

@@ -228,14 +228,14 @@ void rtgui_radiobox_set_orientation(struct rtgui_radiobox *radiobox, int orienta
     if (radiobox->orient == RTGUI_HORIZONTAL)
     {
         /* HORIZONTAL */
-        rtgui_widget_set_miniheight(RTGUI_WIDGET(radiobox), RTGUI_RADIOBOX_DEFAULT_HEIGHT);
-        rtgui_widget_set_miniwidth(RTGUI_WIDGET(radiobox), RTGUI_RADIOBOX_DEFAULT_WIDTH);
+        rtgui_widget_set_minheight(RTGUI_WIDGET(radiobox), RTGUI_RADIOBOX_DEFAULT_HEIGHT);
+        rtgui_widget_set_minwidth(RTGUI_WIDGET(radiobox), RTGUI_RADIOBOX_DEFAULT_WIDTH);
     }
     else
     {
         /* VERTICAL */
-        rtgui_widget_set_miniwidth(RTGUI_WIDGET(radiobox), RTGUI_RADIOBOX_DEFAULT_HEIGHT);
-        rtgui_widget_set_miniheight(RTGUI_WIDGET(radiobox), RTGUI_RADIOBOX_DEFAULT_WIDTH);
+        rtgui_widget_set_minwidth(RTGUI_WIDGET(radiobox), RTGUI_RADIOBOX_DEFAULT_HEIGHT);
+        rtgui_widget_set_minheight(RTGUI_WIDGET(radiobox), RTGUI_RADIOBOX_DEFAULT_WIDTH);
     }
 #endif
 }

+ 4 - 4
components/rtgui/widgets/slider.c

@@ -255,14 +255,14 @@ void rtgui_slider_set_orientation(struct rtgui_slider *slider, int orientation)
     if (slider->orient == RTGUI_HORIZONTAL)
     {
         /* HORIZONTAL */
-        rtgui_widget_set_miniheight(RTGUI_WIDGET(slider), RTGUI_SLIDER_DEFAULT_HEIGHT);
-        rtgui_widget_set_miniwidth(RTGUI_WIDGET(slider), RTGUI_SLIDER_DEFAULT_WIDTH);
+        rtgui_widget_set_minheight(RTGUI_WIDGET(slider), RTGUI_SLIDER_DEFAULT_HEIGHT);
+        rtgui_widget_set_minwidth(RTGUI_WIDGET(slider), RTGUI_SLIDER_DEFAULT_WIDTH);
     }
     else
     {
         /* VERTICAL */
-        rtgui_widget_set_miniwidth(RTGUI_WIDGET(slider), RTGUI_SLIDER_DEFAULT_HEIGHT);
-        rtgui_widget_set_miniheight(RTGUI_WIDGET(slider), RTGUI_SLIDER_DEFAULT_WIDTH);
+        rtgui_widget_set_minwidth(RTGUI_WIDGET(slider), RTGUI_SLIDER_DEFAULT_HEIGHT);
+        rtgui_widget_set_minheight(RTGUI_WIDGET(slider), RTGUI_SLIDER_DEFAULT_WIDTH);
     }
 #endif
 }

+ 4 - 4
components/rtgui/widgets/staticline.c

@@ -73,14 +73,14 @@ void rtgui_staticline_set_orientation(rtgui_staticline_t *staticline, int orient
     if (orientation == RTGUI_HORIZONTAL)
     {
         /* HORIZONTAL */
-        rtgui_widget_set_miniheight(RTGUI_WIDGET(staticline), 2);
-        rtgui_widget_set_miniwidth(RTGUI_WIDGET(staticline), 100);
+        rtgui_widget_set_minheight(RTGUI_WIDGET(staticline), 2);
+        rtgui_widget_set_minwidth(RTGUI_WIDGET(staticline), 100);
     }
     else
     {
         /* VERTICAL */
-        rtgui_widget_set_miniwidth(RTGUI_WIDGET(staticline), 2);
-        rtgui_widget_set_miniheight(RTGUI_WIDGET(staticline), 100);
+        rtgui_widget_set_minwidth(RTGUI_WIDGET(staticline), 2);
+        rtgui_widget_set_minheight(RTGUI_WIDGET(staticline), 100);
     }
 #endif
 }

+ 26 - 20
components/rtgui/widgets/textbox.c

@@ -54,6 +54,14 @@ static void _rtgui_textbox_constructor(rtgui_textbox_t *box)
 	rtgui_textbox_set_mask_char(box, '*');
 
 	rtgui_font_get_metrics(RTGUI_WIDGET_FONT(box), "H", &rect);
+    rtgui_widget_set_minheight(RTGUI_WIDGET(box),
+            rtgui_rect_height(rect) + RTGUI_TEXTBOX_BORDER_WIDTH * 2);
+    /* at least, we want to display one char. */
+    rtgui_widget_set_minwidth(RTGUI_WIDGET(box),
+            rtgui_rect_width(rect) + RTGUI_TEXTBOX_BORDER_WIDTH * 2 \
+            + RTGUI_WIDGET_DEFAULT_MARGIN /* there is a margin in the beginning
+                                             of the text. */
+            );
 	box->font_width = rtgui_rect_width(rect);
 	box->on_enter = RT_NULL;
 	box->dis_length = 0;
@@ -531,13 +539,13 @@ void rtgui_textbox_ondraw(rtgui_textbox_t *box)
 	rtgui_widget_get_rect(RTGUI_WIDGET(box), &rect);
 	fc = RTGUI_WIDGET_FOREGROUND(box);
 
-	rtgui_rect_inflate(&rect, -1);
+	rtgui_rect_inflate(&rect, -RTGUI_TEXTBOX_BORDER_WIDTH);
 
 	/* fill widget rect with white color */
 	RTGUI_WIDGET_BACKGROUND(box) = white;
 	rtgui_dc_fill_rect(dc, &rect);
 
-	rtgui_rect_inflate(&rect, 1);
+	rtgui_rect_inflate(&rect, RTGUI_TEXTBOX_BORDER_WIDTH);
 	/* draw border */
 	RTGUI_WIDGET_FOREGROUND(box) = RTGUI_RGB(123, 158, 189);
 	rtgui_dc_draw_rect(dc, &rect);
@@ -610,29 +618,27 @@ char rtgui_textbox_get_mask_char(rtgui_textbox_t *box)
 	return box->mask_char;
 }
 
-void rtgui_textbox_set_line_length(rtgui_textbox_t *box, rt_size_t length)
+rt_err_t rtgui_textbox_set_line_length(rtgui_textbox_t *box, rt_size_t length)
 {
-	rt_uint8_t *new_line;
+    char *new_line;
 
-	RT_ASSERT(box != RT_NULL);
+    RT_ASSERT(box != RT_NULL);
 
-	/* invalid length */
-	if (length <= 0)
-		return;
+    /* invalid length */
+    if (length <= 0)
+        return -RT_ERROR;
 
-	new_line = rtgui_malloc(length);
-	if (length < box->line_length)
-	{
-		rt_memcpy(new_line, box->text, length - 1);
-		new_line[length] = '\0';
-	}
-	else
-	{
-		rt_memcpy(new_line, (const char *)box->text, rt_strlen((const char *)box->text));
-	}
+    new_line = rtgui_realloc(box->text, length+1);
+    if (new_line == RT_NULL)
+        return -RT_ENOMEM;
+
+    if (length < box->line_length)
+        new_line[length] = '\0';
+
+    box->line_length = length;
+    box->text = new_line;
 
-	/* set line length */
-	box->line_length = length;
+    return RT_EOK;
 }
 
 /* get textbox text area */

+ 17 - 9
components/rtgui/widgets/widget.c

@@ -135,9 +135,9 @@ void rtgui_widget_set_rect(rtgui_widget_t *widget, const rtgui_rect_t *rect)
         rtgui_container_layout(RTGUI_CONTAINER(widget));
     }
 
-    /* reset mini width and height */
-    widget->mini_width  = rtgui_rect_width(widget->extent);
-    widget->mini_height = rtgui_rect_height(widget->extent);
+    /* reset min width and height */
+    widget->min_width  = rtgui_rect_width(widget->extent);
+    widget->min_height = rtgui_rect_height(widget->extent);
 
     /* it's not empty, fini it */
     if (rtgui_region_not_empty(&(widget->clip)))
@@ -184,21 +184,29 @@ void rtgui_widget_get_extent(rtgui_widget_t *widget, rtgui_rect_t *rect)
 }
 RTM_EXPORT(rtgui_widget_get_extent);
 
-void rtgui_widget_set_miniwidth(rtgui_widget_t *widget, int width)
+void rtgui_widget_set_minsize(rtgui_widget_t *widget, int width, int height)
+{
+	RT_ASSERT(widget != RT_NULL);
+	widget->min_width = width;
+	widget->min_height = height;
+}
+RTM_EXPORT(rtgui_widget_set_minsize);
+
+void rtgui_widget_set_minwidth(rtgui_widget_t *widget, int width)
 {
     RT_ASSERT(widget != RT_NULL);
 
-    widget->mini_width = width;
+    widget->min_width = width;
 }
-RTM_EXPORT(rtgui_widget_set_miniwidth);
+RTM_EXPORT(rtgui_widget_set_minwidth);
 
-void rtgui_widget_set_miniheight(rtgui_widget_t *widget, int height)
+void rtgui_widget_set_minheight(rtgui_widget_t *widget, int height)
 {
     RT_ASSERT(widget != RT_NULL);
 
-    widget->mini_height = height;
+    widget->min_height = height;
 }
-RTM_EXPORT(rtgui_widget_set_miniheight);
+RTM_EXPORT(rtgui_widget_set_minheight);
 
 /*
  * This function moves widget and its children to a logic point

+ 30 - 20
components/rtgui/widgets/window.c

@@ -178,7 +178,7 @@ static rt_bool_t _rtgui_win_deal_close(struct rtgui_win *win,
             return RT_FALSE;
     }
 
-    rtgui_win_hiden(win);
+    rtgui_win_hide(win);
 
     win->flag |= RTGUI_WIN_FLAG_CLOSED;
 
@@ -280,7 +280,7 @@ rt_base_t rtgui_win_show(struct rtgui_win *win, rt_bool_t is_modal)
 
     /* set main window */
     if (app->main_object == RT_NULL)
-        rtgui_app_set_main_win(win);
+        rtgui_app_set_main_win(app, win);
 
     if (is_modal == RT_TRUE)
     {
@@ -328,7 +328,7 @@ void rtgui_win_end_modal(struct rtgui_win *win, rtgui_modal_code_t modal_code)
 }
 RTM_EXPORT(rtgui_win_end_modal);
 
-void rtgui_win_hiden(struct rtgui_win *win)
+void rtgui_win_hide(struct rtgui_win *win)
 {
     RT_ASSERT(win != RT_NULL);
 
@@ -351,7 +351,7 @@ void rtgui_win_hiden(struct rtgui_win *win)
         win->flag &= ~RTGUI_WIN_FLAG_ACTIVATE;
     }
 }
-RTM_EXPORT(rtgui_win_hiden);
+RTM_EXPORT(rtgui_win_hide);
 
 rt_err_t rtgui_win_activate(struct rtgui_win *win)
 {
@@ -469,7 +469,7 @@ rt_bool_t rtgui_win_event_handler(struct rtgui_object *object, struct rtgui_even
         break;
 
     case RTGUI_EVENT_WIN_HIDE:
-        rtgui_win_hiden(win);
+        rtgui_win_hide(win);
         break;
 
     case RTGUI_EVENT_WIN_CLOSE:
@@ -538,27 +538,37 @@ rt_bool_t rtgui_win_event_handler(struct rtgui_object *object, struct rtgui_even
         break;
 
     case RTGUI_EVENT_MOUSE_BUTTON:
-        /* check whether has widget which handled mouse event before */
-        if (win->last_mevent_widget != RT_NULL)
-        {
-            RTGUI_OBJECT(win->last_mevent_widget)->event_handler(
-                RTGUI_OBJECT(win->last_mevent_widget),
-                event);
-
-            /* clean last mouse event handled widget */
-            win->last_mevent_widget = RT_NULL;
-        }
-        else if (rtgui_container_dispatch_mouse_event(RTGUI_CONTAINER(win),
-                 (struct rtgui_event_mouse *)event) == RT_FALSE)
         {
+            rt_bool_t res = rtgui_container_dispatch_mouse_event(RTGUI_CONTAINER(win),
+                                        (struct rtgui_event_mouse *)event);
 #ifndef RTGUI_USING_SMALL_SIZE
             if (RTGUI_WIDGET(object)->on_mouseclick != RT_NULL)
             {
-                return RTGUI_WIDGET(object)->on_mouseclick(object, event);
+                RTGUI_WIDGET(object)->on_mouseclick(object, event);
             }
 #endif
+            /* check whether has widget which handled mouse event before.
+             *
+             * Note #1: that the widget should have already received mouse down
+             * event and we should only feed the mouse up event to it here.
+             *
+             * Note #2: the widget is responsible to clean up
+             * last_mevent_widget on mouse up event(but not overwrite other
+             * widgets). If not, it will receive two mouse up events.
+             */
+            if (((struct rtgui_event_mouse *)event)->button & RTGUI_MOUSE_BUTTON_UP
+                    && win->last_mevent_widget != RT_NULL)
+            {
+                RTGUI_OBJECT(win->last_mevent_widget)->event_handler(
+                        RTGUI_OBJECT(win->last_mevent_widget),
+                        event);
+
+                /* clean last mouse event handled widget */
+                win->last_mevent_widget = RT_NULL;
+            }
+
+            return res;
         }
-        break;
 
     case RTGUI_EVENT_MOUSE_MOTION:
 #if 0
@@ -623,7 +633,7 @@ rt_bool_t rtgui_win_event_handler(struct rtgui_object *object, struct rtgui_even
             return RT_TRUE;
         break;
 
-    default :
+    default:
         return rtgui_container_event_handler(object, event);
     }
 

+ 1 - 0
examples/gui/SConscript

@@ -43,6 +43,7 @@ demo_view_edit.c
 demo_view_bmp.c
 demo_plot.c
 mywidget.c
+demo_view_digtube.c
 """)
 
 if GetDepend('RTGUI_USING_FONT_COMPACT'):

+ 2 - 1
examples/gui/demo_application.c

@@ -33,7 +33,7 @@ static void application_entry(void *parameter)
     struct rtgui_app *app;
     struct rtgui_rect rect;
 
-    app = rtgui_app_create(rt_thread_self(), "gui_demo");
+    app = rtgui_app_create("gui_demo");
     if (app == RT_NULL)
         return;
 
@@ -95,6 +95,7 @@ static void application_entry(void *parameter)
     demo_view_notebook();
     demo_view_mywidget();
     demo_plot();
+	demo_view_digtube();
 
 #if defined(RTGUI_USING_DFS_FILERW)
 	demo_view_edit();

+ 8 - 5
examples/gui/demo_plot.c

@@ -42,7 +42,7 @@ struct rtgui_container* demo_plot(void)
     curve1->min_x = 0;
     curve1->max_x = sizeof(sin_ydata)/sizeof(sin_ydata[0]);
     curve1->min_y = -100;
-    curve1->min_y = 100;
+    curve1->max_y = 100;
     curve1->color = red;
     rtgui_mv_model_add_view(RTGUI_MV_MODEL(curve1), RTGUI_MV_VIEW(plot));
 
@@ -51,22 +51,25 @@ struct rtgui_container* demo_plot(void)
     RTGUI_MV_MODEL(curve2)->length = sizeof(cos_ydata)/sizeof(cos_ydata[0]);
     curve2->min_x = 0;
     curve2->max_x = sizeof(cos_ydata)/sizeof(cos_ydata[0]);
-    curve1->min_y = -50;
-    curve1->min_y = 50;
+    curve2->min_y = -50;
+    curve2->max_y = 50;
     curve2->color = blue;
     rtgui_mv_model_add_view(RTGUI_MV_MODEL(curve2), RTGUI_MV_VIEW(plot));
 
     curve3 = rtgui_plot_curve_create();
     rtgui_plot_curve_set_x(curve3, cos_ydata);
     rtgui_plot_curve_set_y(curve3, sin_ydata);
+    curve3->min_x = -50;
+    curve3->max_x = 50;
+    curve3->min_y = -100;
+    curve3->max_y = 100;
     RTGUI_MV_MODEL(curve3)->length = sizeof(sin_ydata)/sizeof(sin_ydata[0]);
     curve3->color = black;
     rtgui_mv_model_add_view(RTGUI_MV_MODEL(curve3), RTGUI_MV_VIEW(plot));
 
     rtgui_widget_get_rect(RTGUI_WIDGET(cnt), &rect);
     rtgui_widget_set_rect(RTGUI_WIDGET(plot), &rect);
-    rtgui_plot_set_base(plot,
-            -rtgui_rect_width(rect)/3, rtgui_rect_height(rect)/2);
+    rtgui_plot_set_base(plot, -100, -300);
 
     rtgui_container_add_child(cnt, RTGUI_WIDGET(plot));
 

+ 2 - 2
examples/gui/demo_view_benchmark.c

@@ -110,7 +110,7 @@ rt_bool_t benchmark_event_handler(struct rtgui_object *object, rtgui_event_t *ev
             if (running)
             {
                 /* stop */
-                rtgui_app_set_onidle(RT_NULL);
+                rtgui_app_set_onidle(rtgui_app_self(), RT_NULL);
                 _draw_default(object, event);
             }
             else
@@ -118,7 +118,7 @@ rt_bool_t benchmark_event_handler(struct rtgui_object *object, rtgui_event_t *ev
                 /* run */
                 ticks = rt_tick_get();
                 area = 0;
-                rtgui_app_set_onidle(_onidle);
+                rtgui_app_set_onidle(rtgui_app_self(), _onidle);
             }
 
             running = !running;

+ 1 - 1
examples/gui/demo_view_box.c

@@ -34,7 +34,7 @@ rtgui_container_t *demo_view_box(void)
 
     button = rtgui_button_create("button 2");
     rtgui_container_add_child(RTGUI_CONTAINER(panel), RTGUI_WIDGET(button));
-    rtgui_widget_set_miniheight(RTGUI_WIDGET(button), 25);
+    rtgui_widget_set_minheight(RTGUI_WIDGET(button), 25);
     RTGUI_WIDGET_ALIGN(button) = RTGUI_ALIGN_EXPAND;
 
     rtgui_container_layout(RTGUI_CONTAINER(panel));

+ 20 - 20
examples/gui/demo_view_button.c

@@ -1,13 +1,13 @@
 /*
- * 绋嬪簭娓呭崟锛歜utton鎺т欢婕旂ず
+ * 程序清单:button控件演示
  *
- * 杩欎釜渚嬪瓙浼氬湪鍒涘缓鍑虹殑container涓婃坊鍔犲嚑涓�笉鍚岀被鍨嬬殑button鎺т欢
+ * 这个例子会在创建出的container上添加几个不同类型的button控件
  */
 
 #include "demo_view.h"
 #include <rtgui/widgets/button.h>
 
-/* 鍒涘缓鐢ㄤ簬婕旂ずbutton鎺т欢鐨勮�鍥� */
+/* 创建用于演示button控件的视图 */
 rtgui_container_t *demo_view_button(void)
 {
     rtgui_rect_t rect;
@@ -15,64 +15,64 @@ rtgui_container_t *demo_view_button(void)
     rtgui_button_t *button;
     rtgui_font_t *font;
 
-    /* 鍏堝垱寤轰竴涓�紨绀虹敤鐨勮�鍥� */
+    /* 先创建一个演示用的视图 */
     container = demo_view("Button View");
 
-    /* 鑾峰緱瑙嗗浘鐨勪綅缃�俊鎭� */
+    /* 获得视图的位置信息 */
     demo_view_get_rect(container, &rect);
     rect.x1 += 5;
     rect.x2 = rect.x1 + 100;
     rect.y1 += 5;
     rect.y2 = rect.y1 + 20;
-    /* 鍒涘缓涓€涓猙utton鎺т欢 */
+    /* 创建一个button控件 */
     button = rtgui_button_create("Red");
-    /* 璁剧疆label鎺т欢鐨勫墠鏅�壊涓虹孩鑹� */
+    /* 设置label控件的前景色为红色 */
     RTGUI_WIDGET_FOREGROUND(button) = red;
-    /* 璁剧疆button鐨勪綅缃� */
+    /* 设置button的位置 */
     rtgui_widget_set_rect(RTGUI_WIDGET(button), &rect);
     rtgui_container_add_child(container, RTGUI_WIDGET(button));
 
-    /* 鑾峰緱瑙嗗浘鐨勪綅缃�俊鎭� */
+    /* 获得视图的位置信息 */
     demo_view_get_rect(container, &rect);
     rect.x1 += 5;
     rect.x2 = rect.x1 + 100;
     rect.y1 += 5 + 25;
     rect.y2 = rect.y1 + 20;
-    /* 鍒涘缓涓€涓猙utton鎺т欢 */
+    /* 创建一个button控件 */
     button = rtgui_button_create("Blue");
-    /* 璁剧疆label鎺т欢鐨勫墠鏅�壊涓鸿摑鑹� */
+    /* 设置label控件的前景色为蓝色 */
     RTGUI_WIDGET_FOREGROUND(button) = blue;
-    /* 璁剧疆button鐨勪綅缃� */
+    /* 设置button的位置 */
     rtgui_widget_set_rect(RTGUI_WIDGET(button), &rect);
     rtgui_container_add_child(container, RTGUI_WIDGET(button));
 
-    /* 鑾峰緱瑙嗗浘鐨勪綅缃�俊鎭� */
+    /* 获得视图的位置信息 */
     demo_view_get_rect(container, &rect);
     rect.x1 += 5;
     rect.x2 = rect.x1 + 100;
     rect.y1 += 5 + 25 + 25;
     rect.y2 = rect.y1 + 20;
-    /* 鍒涘缓涓€涓猙utton鎺т欢 */
+    /* 创建一个button控件 */
     button = rtgui_button_create("12 font");
-    /* 璁剧疆瀛椾綋涓�12鐐归樀鐨刟sc瀛椾綋 */
+    /* 设置字体为12点阵的asc字体 */
     font = rtgui_font_refer("asc", 12);
     RTGUI_WIDGET_FONT(button) = font;
-    /* 璁剧疆button鐨勪綅缃� */
+    /* 设置button的位置 */
     rtgui_widget_set_rect(RTGUI_WIDGET(button), &rect);
     rtgui_container_add_child(container, RTGUI_WIDGET(button));
 
-    /* 鑾峰緱瑙嗗浘鐨勪綅缃�俊鎭� */
+    /* 获得视图的位置信息 */
     demo_view_get_rect(container, &rect);
     rect.x1 += 5;
     rect.x2 = rect.x1 + 100;
     rect.y1 += 5 + 25 + 25 + 25;
     rect.y2 = rect.y1 + 20;
-    /* 鍒涘缓涓€涓猙utton鎺т欢 */
+    /* 创建一个button控件 */
     button = rtgui_button_create("16 font");
-    /* 璁剧疆瀛椾綋涓�16鐐归樀鐨刟sc瀛椾綋 */
+    /* 设置字体为16点阵的asc字体 */
     font = rtgui_font_refer("asc", 16);
     RTGUI_WIDGET_FONT(button) = font;
-    /* 璁剧疆button鐨勪綅缃� */
+    /* 设置button的位置 */
     rtgui_widget_set_rect(RTGUI_WIDGET(button), &rect);
     rtgui_container_add_child(container, RTGUI_WIDGET(button));
 

+ 20 - 20
examples/gui/demo_view_checkbox.c

@@ -1,13 +1,13 @@
 /*
- * 绋嬪簭娓呭崟锛歝heckbox鎺т欢婕旂ず
+ * 程序清单:checkbox控件演示
  *
- * 杩欎釜渚嬪瓙浼氬湪鍒涘缓鍑虹殑container涓婃坊鍔犲嚑涓猚heckbox鎺т欢
+ * 这个例子会在创建出的container上添加几个checkbox控件
  */
 
 #include "demo_view.h"
 #include <rtgui/widgets/checkbox.h>
 
-/* 鍒涘缓鐢ㄤ簬婕旂ずcheckbox鎺т欢鐨勮�鍥� */
+/* 创建用于演示checkbox控件的视图 */
 rtgui_container_t *demo_view_checkbox(void)
 {
     rtgui_rect_t rect;
@@ -15,64 +15,64 @@ rtgui_container_t *demo_view_checkbox(void)
     rtgui_checkbox_t *checkbox;
     rtgui_font_t *font;
 
-    /* 鍏堝垱寤轰竴涓�紨绀虹敤鐨勮�鍥� */
+    /* 先创建一个演示用的视图 */
     container = demo_view("CheckBox View");
 
-    /* 鑾峰緱瑙嗗浘鐨勪綅缃�俊鎭� */
+    /* 获得视图的位置信息 */
     demo_view_get_rect(container, &rect);
     rect.x1 += 5;
     rect.x2 = rect.x1 + 100;
     rect.y1 += 5;
     rect.y2 = rect.y1 + 20;
-    /* 鍒涘缓涓€涓猚heckbox鎺т欢 */
+    /* 创建一个checkbox控件 */
     checkbox = rtgui_checkbox_create("Red", RT_TRUE);
-    /* 璁剧疆鍓嶆櫙鑹蹭负绾㈣壊 */
+    /* 设置前景色为红色 */
     RTGUI_WIDGET_FOREGROUND(checkbox) = red;
-    /* 璁剧疆checkbox鐨勪綅缃� */
+    /* 设置checkbox的位置 */
     rtgui_widget_set_rect(RTGUI_WIDGET(checkbox), &rect);
     rtgui_container_add_child(container, RTGUI_WIDGET(checkbox));
 
-    /* 鑾峰緱瑙嗗浘鐨勪綅缃�俊鎭� */
+    /* 获得视图的位置信息 */
     demo_view_get_rect(container, &rect);
     rect.x1 += 5;
     rect.x2 = rect.x1 + 100;
     rect.y1 += 5 + 25;
     rect.y2 = rect.y1 + 20;
-    /* 鍒涘缓涓€涓猚heckbox鎺т欢 */
+    /* 创建一个checkbox控件 */
     checkbox = rtgui_checkbox_create("Blue", RT_TRUE);
-    /* 璁剧疆鍓嶆櫙鑹蹭负钃濊壊 */
+    /* 设置前景色为蓝色 */
     RTGUI_WIDGET_FOREGROUND(checkbox) = blue;
-    /* 璁剧疆checkbox鐨勪綅缃� */
+    /* 设置checkbox的位置 */
     rtgui_widget_set_rect(RTGUI_WIDGET(checkbox), &rect);
     rtgui_container_add_child(container, RTGUI_WIDGET(checkbox));
 
-    /* 鑾峰緱瑙嗗浘鐨勪綅缃�俊鎭� */
+    /* 获得视图的位置信息 */
     demo_view_get_rect(container, &rect);
     rect.x1 += 5;
     rect.x2 = rect.x1 + 100;
     rect.y1 += 5 + 25 + 25;
     rect.y2 = rect.y1 + 20;
-    /* 鍒涘缓涓€涓猚heckbox鎺т欢 */
+    /* 创建一个checkbox控件 */
     checkbox = rtgui_checkbox_create("12 font", RT_TRUE);
-    /* 璁剧疆瀛椾綋涓�12鐐归樀 */
+    /* 设置字体为12点阵 */
     font = rtgui_font_refer("asc", 12);
     RTGUI_WIDGET_FONT(checkbox) = font;
-    /* 璁剧疆checkbox鐨勪綅缃� */
+    /* 设置checkbox的位置 */
     rtgui_widget_set_rect(RTGUI_WIDGET(checkbox), &rect);
     rtgui_container_add_child(container, RTGUI_WIDGET(checkbox));
 
-    /* 鑾峰緱瑙嗗浘鐨勪綅缃�俊鎭� */
+    /* 获得视图的位置信息 */
     demo_view_get_rect(container, &rect);
     rect.x1 += 5;
     rect.x2 = rect.x1 + 100;
     rect.y1 += 5 + 25 + 25 + 25;
     rect.y2 = rect.y1 + 20;
-    /* 鍒涘缓涓€涓猚heckbox鎺т欢 */
+    /* 创建一个checkbox控件 */
     checkbox = rtgui_checkbox_create("16 font", RT_TRUE);
-    /* 璁剧疆瀛椾綋涓�16鐐归樀 */
+    /* 设置字体为16点阵 */
     font = rtgui_font_refer("asc", 16);
     RTGUI_WIDGET_FONT(checkbox) = font;
-    /* 璁剧疆checkbox鐨勪綅缃� */
+    /* 设置checkbox的位置 */
     rtgui_widget_set_rect(RTGUI_WIDGET(checkbox), &rect);
     rtgui_container_add_child(container, RTGUI_WIDGET(checkbox));
 

Some files were not shown because too many files changed in this diff