Pratt 1.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.exrc +61 -0
- data/.gitignore +4 -0
- data/History.txt +6 -0
- data/Manifest.txt +46 -0
- data/Pratt.gemspec +351 -0
- data/README.txt +66 -0
- data/Rakefile +85 -0
- data/TODO +54 -0
- data/VERSION +1 -0
- data/bin/pratt.rb +13 -0
- data/config.rb +34 -0
- data/lib/pratt.rb +527 -0
- data/lib/pratt/array.rb +11 -0
- data/lib/pratt/string.rb +18 -0
- data/models/app.rb +40 -0
- data/models/customer.rb +24 -0
- data/models/payment.rb +22 -0
- data/models/pratt.rb +19 -0
- data/models/project.rb +82 -0
- data/models/whence.rb +70 -0
- data/pkgs/tile-0.8.2.tar.gz +0 -0
- data/pkgs/tile-0.8.2/ANNOUNCE.txt +95 -0
- data/pkgs/tile-0.8.2/ChangeLog +4651 -0
- data/pkgs/tile-0.8.2/Makefile +250 -0
- data/pkgs/tile-0.8.2/Makefile.in +250 -0
- data/pkgs/tile-0.8.2/README.txt +86 -0
- data/pkgs/tile-0.8.2/aclocal.m4 +2 -0
- data/pkgs/tile-0.8.2/altTheme.o +0 -0
- data/pkgs/tile-0.8.2/blink.o +0 -0
- data/pkgs/tile-0.8.2/button.o +0 -0
- data/pkgs/tile-0.8.2/cache.o +0 -0
- data/pkgs/tile-0.8.2/clamTheme.o +0 -0
- data/pkgs/tile-0.8.2/classicTheme.o +0 -0
- data/pkgs/tile-0.8.2/config.log +1330 -0
- data/pkgs/tile-0.8.2/config.status +795 -0
- data/pkgs/tile-0.8.2/configure +15248 -0
- data/pkgs/tile-0.8.2/configure.in +89 -0
- data/pkgs/tile-0.8.2/demos/autocomplete.tcl +59 -0
- data/pkgs/tile-0.8.2/demos/demo.tcl +870 -0
- data/pkgs/tile-0.8.2/demos/dirbrowser.tcl +167 -0
- data/pkgs/tile-0.8.2/demos/dlgtest.tcl +97 -0
- data/pkgs/tile-0.8.2/demos/iconlib.tcl +110 -0
- data/pkgs/tile-0.8.2/demos/repeater.tcl +117 -0
- data/pkgs/tile-0.8.2/demos/toolbutton.tcl +101 -0
- data/pkgs/tile-0.8.2/doc/Geometry.3 +230 -0
- data/pkgs/tile-0.8.2/doc/INDEX.MAP +153 -0
- data/pkgs/tile-0.8.2/doc/Makefile +36 -0
- data/pkgs/tile-0.8.2/doc/TILE.XML +45 -0
- data/pkgs/tile-0.8.2/doc/Theme.3 +34 -0
- data/pkgs/tile-0.8.2/doc/button.n +75 -0
- data/pkgs/tile-0.8.2/doc/checkbutton.n +61 -0
- data/pkgs/tile-0.8.2/doc/combobox.n +98 -0
- data/pkgs/tile-0.8.2/doc/converting.txt +97 -0
- data/pkgs/tile-0.8.2/doc/dialog.n +122 -0
- data/pkgs/tile-0.8.2/doc/entry.n +438 -0
- data/pkgs/tile-0.8.2/doc/frame.n +43 -0
- data/pkgs/tile-0.8.2/doc/html/Geometry.html +304 -0
- data/pkgs/tile-0.8.2/doc/html/Theme.html +48 -0
- data/pkgs/tile-0.8.2/doc/html/button.html +120 -0
- data/pkgs/tile-0.8.2/doc/html/category-index.html +18 -0
- data/pkgs/tile-0.8.2/doc/html/checkbutton.html +94 -0
- data/pkgs/tile-0.8.2/doc/html/combobox.html +164 -0
- data/pkgs/tile-0.8.2/doc/html/converting.txt +97 -0
- data/pkgs/tile-0.8.2/doc/html/dialog.html +159 -0
- data/pkgs/tile-0.8.2/doc/html/entry.html +613 -0
- data/pkgs/tile-0.8.2/doc/html/frame.html +76 -0
- data/pkgs/tile-0.8.2/doc/html/image.html +100 -0
- data/pkgs/tile-0.8.2/doc/html/index.html +25 -0
- data/pkgs/tile-0.8.2/doc/html/keyword-index.html +228 -0
- data/pkgs/tile-0.8.2/doc/html/label.html +133 -0
- data/pkgs/tile-0.8.2/doc/html/labelframe.html +91 -0
- data/pkgs/tile-0.8.2/doc/html/manpage.css +212 -0
- data/pkgs/tile-0.8.2/doc/html/menubutton.html +63 -0
- data/pkgs/tile-0.8.2/doc/html/notebook.html +280 -0
- data/pkgs/tile-0.8.2/doc/html/paned.html +149 -0
- data/pkgs/tile-0.8.2/doc/html/progressbar.html +138 -0
- data/pkgs/tile-0.8.2/doc/html/radiobutton.html +89 -0
- data/pkgs/tile-0.8.2/doc/html/scrollbar.html +221 -0
- data/pkgs/tile-0.8.2/doc/html/separator.html +48 -0
- data/pkgs/tile-0.8.2/doc/html/sizegrip.html +62 -0
- data/pkgs/tile-0.8.2/doc/html/style.html +172 -0
- data/pkgs/tile-0.8.2/doc/html/tile-intro.html +164 -0
- data/pkgs/tile-0.8.2/doc/html/treeview.html +634 -0
- data/pkgs/tile-0.8.2/doc/html/widget.html +342 -0
- data/pkgs/tile-0.8.2/doc/image.n +81 -0
- data/pkgs/tile-0.8.2/doc/internals.txt +409 -0
- data/pkgs/tile-0.8.2/doc/label.n +75 -0
- data/pkgs/tile-0.8.2/doc/labelframe.n +64 -0
- data/pkgs/tile-0.8.2/doc/man.macros +239 -0
- data/pkgs/tile-0.8.2/doc/menubutton.n +41 -0
- data/pkgs/tile-0.8.2/doc/notebook.n +188 -0
- data/pkgs/tile-0.8.2/doc/paned.n +95 -0
- data/pkgs/tile-0.8.2/doc/progressbar.n +79 -0
- data/pkgs/tile-0.8.2/doc/radiobutton.n +57 -0
- data/pkgs/tile-0.8.2/doc/scrollbar.n +160 -0
- data/pkgs/tile-0.8.2/doc/separator.n +30 -0
- data/pkgs/tile-0.8.2/doc/sizegrip.n +53 -0
- data/pkgs/tile-0.8.2/doc/style.n +119 -0
- data/pkgs/tile-0.8.2/doc/tile-intro.n +165 -0
- data/pkgs/tile-0.8.2/doc/tmml.options +4 -0
- data/pkgs/tile-0.8.2/doc/treeview.n +415 -0
- data/pkgs/tile-0.8.2/doc/widget.n +227 -0
- data/pkgs/tile-0.8.2/doc/xml/Geometry.tmml +379 -0
- data/pkgs/tile-0.8.2/doc/xml/INDEX.MAP +153 -0
- data/pkgs/tile-0.8.2/doc/xml/Theme.tmml +63 -0
- data/pkgs/tile-0.8.2/doc/xml/button.tmml +134 -0
- data/pkgs/tile-0.8.2/doc/xml/checkbutton.tmml +119 -0
- data/pkgs/tile-0.8.2/doc/xml/combobox.tmml +184 -0
- data/pkgs/tile-0.8.2/doc/xml/dialog.tmml +195 -0
- data/pkgs/tile-0.8.2/doc/xml/entry.tmml +630 -0
- data/pkgs/tile-0.8.2/doc/xml/frame.tmml +98 -0
- data/pkgs/tile-0.8.2/doc/xml/image.tmml +101 -0
- data/pkgs/tile-0.8.2/doc/xml/label.tmml +154 -0
- data/pkgs/tile-0.8.2/doc/xml/labelframe.tmml +116 -0
- data/pkgs/tile-0.8.2/doc/xml/menubutton.tmml +80 -0
- data/pkgs/tile-0.8.2/doc/xml/notebook.tmml +306 -0
- data/pkgs/tile-0.8.2/doc/xml/paned.tmml +154 -0
- data/pkgs/tile-0.8.2/doc/xml/progressbar.tmml +151 -0
- data/pkgs/tile-0.8.2/doc/xml/radiobutton.tmml +109 -0
- data/pkgs/tile-0.8.2/doc/xml/scrollbar.tmml +233 -0
- data/pkgs/tile-0.8.2/doc/xml/separator.tmml +59 -0
- data/pkgs/tile-0.8.2/doc/xml/sizegrip.tmml +82 -0
- data/pkgs/tile-0.8.2/doc/xml/style.tmml +171 -0
- data/pkgs/tile-0.8.2/doc/xml/tile-intro.tmml +192 -0
- data/pkgs/tile-0.8.2/doc/xml/treeview.tmml +604 -0
- data/pkgs/tile-0.8.2/doc/xml/widget.tmml +372 -0
- data/pkgs/tile-0.8.2/entry.o +0 -0
- data/pkgs/tile-0.8.2/frame.o +0 -0
- data/pkgs/tile-0.8.2/generic/Makefile.in +221 -0
- data/pkgs/tile-0.8.2/generic/TODO +493 -0
- data/pkgs/tile-0.8.2/generic/altTheme.c +1172 -0
- data/pkgs/tile-0.8.2/generic/blink.c +168 -0
- data/pkgs/tile-0.8.2/generic/button.c +858 -0
- data/pkgs/tile-0.8.2/generic/cache.c +354 -0
- data/pkgs/tile-0.8.2/generic/clamTheme.c +974 -0
- data/pkgs/tile-0.8.2/generic/classicTheme.c +518 -0
- data/pkgs/tile-0.8.2/generic/configure +10334 -0
- data/pkgs/tile-0.8.2/generic/configure.in +100 -0
- data/pkgs/tile-0.8.2/generic/entry.c +1922 -0
- data/pkgs/tile-0.8.2/generic/frame.c +648 -0
- data/pkgs/tile-0.8.2/generic/gunk.h +44 -0
- data/pkgs/tile-0.8.2/generic/image.c +416 -0
- data/pkgs/tile-0.8.2/generic/label.c +663 -0
- data/pkgs/tile-0.8.2/generic/layout.c +1215 -0
- data/pkgs/tile-0.8.2/generic/manager.c +554 -0
- data/pkgs/tile-0.8.2/generic/manager.h +91 -0
- data/pkgs/tile-0.8.2/generic/notebook.c +1380 -0
- data/pkgs/tile-0.8.2/generic/paned.c +958 -0
- data/pkgs/tile-0.8.2/generic/pkgIndex.tcl.in +7 -0
- data/pkgs/tile-0.8.2/generic/progress.c +549 -0
- data/pkgs/tile-0.8.2/generic/scale.c +526 -0
- data/pkgs/tile-0.8.2/generic/scroll.c +253 -0
- data/pkgs/tile-0.8.2/generic/scrollbar.c +346 -0
- data/pkgs/tile-0.8.2/generic/separator.c +132 -0
- data/pkgs/tile-0.8.2/generic/square.c +306 -0
- data/pkgs/tile-0.8.2/generic/tagset.c +147 -0
- data/pkgs/tile-0.8.2/generic/tile.c +296 -0
- data/pkgs/tile-0.8.2/generic/tkElements.c +1280 -0
- data/pkgs/tile-0.8.2/generic/tkTheme.c +1708 -0
- data/pkgs/tile-0.8.2/generic/tkTheme.h +419 -0
- data/pkgs/tile-0.8.2/generic/tkThemeInt.h +45 -0
- data/pkgs/tile-0.8.2/generic/tkstate.c +268 -0
- data/pkgs/tile-0.8.2/generic/trace.c +145 -0
- data/pkgs/tile-0.8.2/generic/track.c +174 -0
- data/pkgs/tile-0.8.2/generic/treeview.c +3211 -0
- data/pkgs/tile-0.8.2/generic/ttk.decls +154 -0
- data/pkgs/tile-0.8.2/generic/ttkDecls.h +340 -0
- data/pkgs/tile-0.8.2/generic/ttkStubInit.c +61 -0
- data/pkgs/tile-0.8.2/generic/ttkStubLib.c +70 -0
- data/pkgs/tile-0.8.2/generic/widget.c +785 -0
- data/pkgs/tile-0.8.2/generic/widget.h +263 -0
- data/pkgs/tile-0.8.2/image.o +0 -0
- data/pkgs/tile-0.8.2/label.o +0 -0
- data/pkgs/tile-0.8.2/layout.o +0 -0
- data/pkgs/tile-0.8.2/library/altTheme.tcl +101 -0
- data/pkgs/tile-0.8.2/library/aquaTheme.tcl +62 -0
- data/pkgs/tile-0.8.2/library/button.tcl +85 -0
- data/pkgs/tile-0.8.2/library/clamTheme.tcl +139 -0
- data/pkgs/tile-0.8.2/library/classicTheme.tcl +108 -0
- data/pkgs/tile-0.8.2/library/combobox.tcl +439 -0
- data/pkgs/tile-0.8.2/library/cursors.tcl +36 -0
- data/pkgs/tile-0.8.2/library/defaults.tcl +118 -0
- data/pkgs/tile-0.8.2/library/dialog.tcl +274 -0
- data/pkgs/tile-0.8.2/library/entry.tcl +580 -0
- data/pkgs/tile-0.8.2/library/fonts.tcl +153 -0
- data/pkgs/tile-0.8.2/library/icons.tcl +105 -0
- data/pkgs/tile-0.8.2/library/keynav.tcl +192 -0
- data/pkgs/tile-0.8.2/library/menubutton.tcl +171 -0
- data/pkgs/tile-0.8.2/library/notebook.tcl +193 -0
- data/pkgs/tile-0.8.2/library/paned.tcl +87 -0
- data/pkgs/tile-0.8.2/library/progress.tcl +51 -0
- data/pkgs/tile-0.8.2/library/scale.tcl +54 -0
- data/pkgs/tile-0.8.2/library/scrollbar.tcl +125 -0
- data/pkgs/tile-0.8.2/library/sizegrip.tcl +77 -0
- data/pkgs/tile-0.8.2/library/tile.tcl +211 -0
- data/pkgs/tile-0.8.2/library/treeview.tcl +382 -0
- data/pkgs/tile-0.8.2/library/utils.tcl +254 -0
- data/pkgs/tile-0.8.2/library/winTheme.tcl +77 -0
- data/pkgs/tile-0.8.2/library/xpTheme.tcl +63 -0
- data/pkgs/tile-0.8.2/libtile0.8.2.so +0 -0
- data/pkgs/tile-0.8.2/libttkstub.a +0 -0
- data/pkgs/tile-0.8.2/license.terms +24 -0
- data/pkgs/tile-0.8.2/macosx/aquaTheme.c +1076 -0
- data/pkgs/tile-0.8.2/manager.o +0 -0
- data/pkgs/tile-0.8.2/notebook.o +0 -0
- data/pkgs/tile-0.8.2/paned.o +0 -0
- data/pkgs/tile-0.8.2/pkgIndex.tcl +3 -0
- data/pkgs/tile-0.8.2/progress.o +0 -0
- data/pkgs/tile-0.8.2/scale.o +0 -0
- data/pkgs/tile-0.8.2/scroll.o +0 -0
- data/pkgs/tile-0.8.2/scrollbar.o +0 -0
- data/pkgs/tile-0.8.2/separator.o +0 -0
- data/pkgs/tile-0.8.2/tagset.o +0 -0
- data/pkgs/tile-0.8.2/tclconfig/install-sh +119 -0
- data/pkgs/tile-0.8.2/tclconfig/tcl.m4 +4069 -0
- data/pkgs/tile-0.8.2/tclconfig/teax.m4 +109 -0
- data/pkgs/tile-0.8.2/tests/all.tcl +18 -0
- data/pkgs/tile-0.8.2/tests/bwidget.test +103 -0
- data/pkgs/tile-0.8.2/tests/cbtest.tcl +125 -0
- data/pkgs/tile-0.8.2/tests/combobox.test +51 -0
- data/pkgs/tile-0.8.2/tests/compound.tcl +92 -0
- data/pkgs/tile-0.8.2/tests/entry.test +285 -0
- data/pkgs/tile-0.8.2/tests/entrytest.tcl +78 -0
- data/pkgs/tile-0.8.2/tests/image.test +94 -0
- data/pkgs/tile-0.8.2/tests/labelframe.tcl +41 -0
- data/pkgs/tile-0.8.2/tests/labelframe.test +137 -0
- data/pkgs/tile-0.8.2/tests/layout.test +33 -0
- data/pkgs/tile-0.8.2/tests/misc.test +35 -0
- data/pkgs/tile-0.8.2/tests/nbtest.tcl +66 -0
- data/pkgs/tile-0.8.2/tests/notebook.test +500 -0
- data/pkgs/tile-0.8.2/tests/paned.test +298 -0
- data/pkgs/tile-0.8.2/tests/progress.test +92 -0
- data/pkgs/tile-0.8.2/tests/pwtest.tcl +90 -0
- data/pkgs/tile-0.8.2/tests/sbtest.tcl +79 -0
- data/pkgs/tile-0.8.2/tests/scrollbar.test +77 -0
- data/pkgs/tile-0.8.2/tests/sgtest.tcl +52 -0
- data/pkgs/tile-0.8.2/tests/testutils.tcl +20 -0
- data/pkgs/tile-0.8.2/tests/tile.test +674 -0
- data/pkgs/tile-0.8.2/tests/treetags.test +78 -0
- data/pkgs/tile-0.8.2/tests/treeview.test +563 -0
- data/pkgs/tile-0.8.2/tests/tvtest.tcl +332 -0
- data/pkgs/tile-0.8.2/tests/validate.test +278 -0
- data/pkgs/tile-0.8.2/tile.o +0 -0
- data/pkgs/tile-0.8.2/tkElements.o +0 -0
- data/pkgs/tile-0.8.2/tkTheme.o +0 -0
- data/pkgs/tile-0.8.2/tkstate.o +0 -0
- data/pkgs/tile-0.8.2/tools/genStubs.tcl +861 -0
- data/pkgs/tile-0.8.2/trace.o +0 -0
- data/pkgs/tile-0.8.2/track.o +0 -0
- data/pkgs/tile-0.8.2/treeview.o +0 -0
- data/pkgs/tile-0.8.2/ttkStubInit.o +0 -0
- data/pkgs/tile-0.8.2/ttkStubLib.o +0 -0
- data/pkgs/tile-0.8.2/widget.o +0 -0
- data/pkgs/tile-0.8.2/win/Tile.dsp +261 -0
- data/pkgs/tile-0.8.2/win/makefile.vc +527 -0
- data/pkgs/tile-0.8.2/win/monitor.c +164 -0
- data/pkgs/tile-0.8.2/win/nmakehlp.c +483 -0
- data/pkgs/tile-0.8.2/win/rules.vc +512 -0
- data/pkgs/tile-0.8.2/win/tile.rc +40 -0
- data/pkgs/tile-0.8.2/win/winTheme.c +734 -0
- data/pkgs/tile-0.8.2/win/xpTheme.c +1029 -0
- data/spec/app_spec.rb +48 -0
- data/spec/customer_spec.rb +31 -0
- data/spec/fixtures/graph.expectation +18 -0
- data/spec/payment_spec.rb +19 -0
- data/spec/pratt_spec.rb +148 -0
- data/spec/project_spec.rb +163 -0
- data/spec/rcov.opts +0 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/whence_spec.rb +54 -0
- data/tasks/pratt.rb +84 -0
- data/templates/model.eruby +12 -0
- data/templates/spec.eruby +8 -0
- data/views/env.rb +22 -0
- data/views/graph.eruby +20 -0
- data/views/invoice.eruby +148 -0
- data/views/main.rb +92 -0
- data/views/pid.eruby +3 -0
- data/views/pop.rb +94 -0
- data/views/pop2.rb +75 -0
- data/views/raw.eruby +11 -0
- metadata +390 -0
|
@@ -0,0 +1,1708 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ttkTheme.c --
|
|
3
|
+
*
|
|
4
|
+
* This file implements the widget styles and themes support.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2002 Frederic Bonnet
|
|
7
|
+
* Copyright (c) 2003 Joe English
|
|
8
|
+
*
|
|
9
|
+
* See the file "license.terms" for information on usage and redistribution
|
|
10
|
+
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
|
11
|
+
*
|
|
12
|
+
* tkTheme.c,v 1.101 2007/12/12 01:19:00 jenglish Exp
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
#include <stdlib.h>
|
|
16
|
+
#include <string.h>
|
|
17
|
+
#include <tk.h>
|
|
18
|
+
#include "tkThemeInt.h"
|
|
19
|
+
|
|
20
|
+
#ifdef NO_PRIVATE_HEADERS
|
|
21
|
+
EXTERN CONST Tk_OptionSpec *TkGetOptionSpec (CONST char *name,
|
|
22
|
+
Tk_OptionTable optionTable);
|
|
23
|
+
#else
|
|
24
|
+
#include <tkInt.h>
|
|
25
|
+
#endif
|
|
26
|
+
|
|
27
|
+
/*------------------------------------------------------------------------
|
|
28
|
+
* +++ Styles.
|
|
29
|
+
*
|
|
30
|
+
* Invariants:
|
|
31
|
+
* If styleName contains a dot, parentStyle->styleName is everything
|
|
32
|
+
* after the first dot; otherwise, parentStyle is the theme's root
|
|
33
|
+
* style ".". The root style's parentStyle is NULL.
|
|
34
|
+
*
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
typedef struct Ttk_Style_
|
|
38
|
+
{
|
|
39
|
+
const char *styleName; /* points to hash table key */
|
|
40
|
+
Tcl_HashTable settingsTable; /* KEY: string; VALUE: StateMap */
|
|
41
|
+
Tcl_HashTable defaultsTable; /* KEY: string; VALUE: resource */
|
|
42
|
+
Ttk_LayoutTemplate layoutTemplate; /* Layout template for style, or NULL */
|
|
43
|
+
Ttk_Style parentStyle; /* Previous style in chain */
|
|
44
|
+
Ttk_ResourceCache cache; /* Back-pointer to resource cache */
|
|
45
|
+
} Style;
|
|
46
|
+
|
|
47
|
+
static Style *NewStyle()
|
|
48
|
+
{
|
|
49
|
+
Style *stylePtr = (Style*)ckalloc(sizeof(Style));
|
|
50
|
+
|
|
51
|
+
stylePtr->styleName = NULL;
|
|
52
|
+
stylePtr->parentStyle = NULL;
|
|
53
|
+
stylePtr->layoutTemplate = NULL;
|
|
54
|
+
stylePtr->cache = NULL;
|
|
55
|
+
Tcl_InitHashTable(&stylePtr->settingsTable, TCL_STRING_KEYS);
|
|
56
|
+
Tcl_InitHashTable(&stylePtr->defaultsTable, TCL_STRING_KEYS);
|
|
57
|
+
|
|
58
|
+
return stylePtr;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
static void FreeStyle(Style *stylePtr)
|
|
62
|
+
{
|
|
63
|
+
Tcl_HashSearch search;
|
|
64
|
+
Tcl_HashEntry *entryPtr;
|
|
65
|
+
|
|
66
|
+
entryPtr = Tcl_FirstHashEntry(&stylePtr->settingsTable, &search);
|
|
67
|
+
while (entryPtr != NULL) {
|
|
68
|
+
Ttk_StateMap stateMap = (Ttk_StateMap)Tcl_GetHashValue(entryPtr);
|
|
69
|
+
Tcl_DecrRefCount(stateMap);
|
|
70
|
+
entryPtr = Tcl_NextHashEntry(&search);
|
|
71
|
+
}
|
|
72
|
+
Tcl_DeleteHashTable(&stylePtr->settingsTable);
|
|
73
|
+
|
|
74
|
+
entryPtr = Tcl_FirstHashEntry(&stylePtr->defaultsTable, &search);
|
|
75
|
+
while (entryPtr != NULL) {
|
|
76
|
+
Tcl_Obj *defaultValue = (Ttk_StateMap)Tcl_GetHashValue(entryPtr);
|
|
77
|
+
Tcl_DecrRefCount(defaultValue);
|
|
78
|
+
entryPtr = Tcl_NextHashEntry(&search);
|
|
79
|
+
}
|
|
80
|
+
Tcl_DeleteHashTable(&stylePtr->defaultsTable);
|
|
81
|
+
|
|
82
|
+
Ttk_FreeLayoutTemplate(stylePtr->layoutTemplate);
|
|
83
|
+
|
|
84
|
+
ckfree((char*)stylePtr);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/*
|
|
88
|
+
* LookupStateMap --
|
|
89
|
+
* Look up dynamic resource settings in the in the specified style.
|
|
90
|
+
*/
|
|
91
|
+
|
|
92
|
+
static Ttk_StateMap LookupStateMap(Ttk_Style stylePtr, const char *optionName)
|
|
93
|
+
{
|
|
94
|
+
while (stylePtr) {
|
|
95
|
+
Tcl_HashEntry *entryPtr =
|
|
96
|
+
Tcl_FindHashEntry(&stylePtr->settingsTable, optionName);
|
|
97
|
+
if (entryPtr)
|
|
98
|
+
return (Ttk_StateMap)Tcl_GetHashValue(entryPtr);
|
|
99
|
+
stylePtr = stylePtr->parentStyle;
|
|
100
|
+
}
|
|
101
|
+
return 0;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/*
|
|
105
|
+
* LookupDefault --
|
|
106
|
+
* Look up default resource setting the in the specified style.
|
|
107
|
+
*/
|
|
108
|
+
static Tcl_Obj *LookupDefault(Ttk_Style stylePtr, const char *optionName)
|
|
109
|
+
{
|
|
110
|
+
while (stylePtr) {
|
|
111
|
+
Tcl_HashEntry *entryPtr =
|
|
112
|
+
Tcl_FindHashEntry(&stylePtr->defaultsTable, optionName);
|
|
113
|
+
if (entryPtr)
|
|
114
|
+
return (Tcl_Obj *)Tcl_GetHashValue(entryPtr);
|
|
115
|
+
stylePtr = stylePtr->parentStyle;
|
|
116
|
+
}
|
|
117
|
+
return 0;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/*------------------------------------------------------------------------
|
|
121
|
+
* +++ Elements.
|
|
122
|
+
*/
|
|
123
|
+
typedef const Tk_OptionSpec **OptionMap;
|
|
124
|
+
/* array of Tk_OptionSpecs mapping widget options to element options */
|
|
125
|
+
|
|
126
|
+
typedef struct Ttk_ElementImpl_ /* Element implementation */
|
|
127
|
+
{
|
|
128
|
+
const char *name; /* Points to hash table key */
|
|
129
|
+
Ttk_ElementSpec *specPtr; /* Template provided during registration. */
|
|
130
|
+
void *clientData; /* Client data passed in at registration time */
|
|
131
|
+
void *elementRecord; /* Scratch buffer for element record storage */
|
|
132
|
+
int nResources; /* #Element options */
|
|
133
|
+
Tcl_Obj **defaultValues; /* Array of option default values */
|
|
134
|
+
Tcl_HashTable optMapCache; /* Map: Tk_OptionTable * -> OptionMap */
|
|
135
|
+
} ElementImpl;
|
|
136
|
+
|
|
137
|
+
/* TTKGetOptionSpec --
|
|
138
|
+
* Look up a Tk_OptionSpec by name from a Tk_OptionTable,
|
|
139
|
+
* and verify that it's compatible with the specified Tk_OptionType,
|
|
140
|
+
* along with other constraints (see below).
|
|
141
|
+
*/
|
|
142
|
+
static const Tk_OptionSpec *TTKGetOptionSpec(
|
|
143
|
+
const char *optionName,
|
|
144
|
+
Tk_OptionTable optionTable,
|
|
145
|
+
Tk_OptionType optionType)
|
|
146
|
+
{
|
|
147
|
+
const Tk_OptionSpec *optionSpec = TkGetOptionSpec(optionName, optionTable);
|
|
148
|
+
|
|
149
|
+
if (!optionSpec)
|
|
150
|
+
return 0;
|
|
151
|
+
|
|
152
|
+
/* Make sure widget option has a Tcl_Obj* entry:
|
|
153
|
+
*/
|
|
154
|
+
if (optionSpec->objOffset < 0) {
|
|
155
|
+
return 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/* Grrr. Ignore accidental mismatches caused by prefix-matching:
|
|
159
|
+
*/
|
|
160
|
+
if (strcmp(optionSpec->optionName, optionName)) {
|
|
161
|
+
return 0;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* Ensure that the widget option type is compatible with
|
|
165
|
+
* the element option type.
|
|
166
|
+
*
|
|
167
|
+
* TK_OPTION_STRING element options are compatible with anything.
|
|
168
|
+
* As a workaround for the workaround for Bug #967209,
|
|
169
|
+
* TK_OPTION_STRING widget options are also compatible with anything
|
|
170
|
+
* (see <<NOTE-NULLOPTIONS>>).
|
|
171
|
+
*/
|
|
172
|
+
if ( optionType != TK_OPTION_STRING
|
|
173
|
+
&& optionSpec->type != TK_OPTION_STRING
|
|
174
|
+
&& optionType != optionSpec->type)
|
|
175
|
+
{
|
|
176
|
+
return 0;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return optionSpec;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/* BuildOptionMap --
|
|
183
|
+
* Construct the mapping from element options to widget options.
|
|
184
|
+
*/
|
|
185
|
+
static OptionMap
|
|
186
|
+
BuildOptionMap(ElementImpl *elementImpl, Tk_OptionTable optionTable)
|
|
187
|
+
{
|
|
188
|
+
OptionMap optionMap = (OptionMap)ckalloc(
|
|
189
|
+
sizeof(const Tk_OptionSpec) * elementImpl->nResources);
|
|
190
|
+
int i;
|
|
191
|
+
|
|
192
|
+
for (i = 0; i < elementImpl->nResources; ++i) {
|
|
193
|
+
Ttk_ElementOptionSpec *e = elementImpl->specPtr->options+i;
|
|
194
|
+
optionMap[i] = TTKGetOptionSpec(e->optionName, optionTable, e->type);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return optionMap;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/* GetOptionMap --
|
|
201
|
+
* Return a cached OptionMap matching the specified optionTable
|
|
202
|
+
* for the specified element, creating it if necessary.
|
|
203
|
+
*/
|
|
204
|
+
static OptionMap
|
|
205
|
+
GetOptionMap(ElementImpl *elementImpl, Tk_OptionTable optionTable)
|
|
206
|
+
{
|
|
207
|
+
OptionMap optionMap;
|
|
208
|
+
int isNew;
|
|
209
|
+
Tcl_HashEntry *entryPtr = Tcl_CreateHashEntry(
|
|
210
|
+
&elementImpl->optMapCache, (ClientData)optionTable, &isNew);
|
|
211
|
+
|
|
212
|
+
if (isNew) {
|
|
213
|
+
optionMap = BuildOptionMap(elementImpl, optionTable);
|
|
214
|
+
Tcl_SetHashValue(entryPtr, optionMap);
|
|
215
|
+
} else {
|
|
216
|
+
optionMap = (OptionMap)(Tcl_GetHashValue(entryPtr));
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return optionMap;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/*
|
|
223
|
+
* NewElementImpl --
|
|
224
|
+
* Allocate and initialize an element implementation record
|
|
225
|
+
* from the specified element specification.
|
|
226
|
+
*/
|
|
227
|
+
static ElementImpl *
|
|
228
|
+
NewElementImpl(const char *name, Ttk_ElementSpec *specPtr,void *clientData)
|
|
229
|
+
{
|
|
230
|
+
ElementImpl *elementImpl = (ElementImpl*)ckalloc(sizeof(ElementImpl));
|
|
231
|
+
int i;
|
|
232
|
+
|
|
233
|
+
elementImpl->name = name;
|
|
234
|
+
elementImpl->specPtr = specPtr;
|
|
235
|
+
elementImpl->clientData = clientData;
|
|
236
|
+
elementImpl->elementRecord = ckalloc(specPtr->elementSize);
|
|
237
|
+
|
|
238
|
+
/* Count #element resources:
|
|
239
|
+
*/
|
|
240
|
+
for (i = 0; specPtr->options[i].optionName != 0; ++i)
|
|
241
|
+
continue;
|
|
242
|
+
elementImpl->nResources = i;
|
|
243
|
+
|
|
244
|
+
/* Initialize default values:
|
|
245
|
+
*/
|
|
246
|
+
elementImpl->defaultValues = (Tcl_Obj**)
|
|
247
|
+
ckalloc(elementImpl->nResources * sizeof(Tcl_Obj *));
|
|
248
|
+
for (i=0; i < elementImpl->nResources; ++i) {
|
|
249
|
+
const char *defaultValue = specPtr->options[i].defaultValue;
|
|
250
|
+
if (defaultValue) {
|
|
251
|
+
elementImpl->defaultValues[i] = Tcl_NewStringObj(defaultValue,-1);
|
|
252
|
+
Tcl_IncrRefCount(elementImpl->defaultValues[i]);
|
|
253
|
+
} else {
|
|
254
|
+
elementImpl->defaultValues[i] = 0;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/* Initialize option map cache:
|
|
259
|
+
*/
|
|
260
|
+
Tcl_InitHashTable(&elementImpl->optMapCache, TCL_ONE_WORD_KEYS);
|
|
261
|
+
|
|
262
|
+
return elementImpl;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/*
|
|
266
|
+
* FreeElementImpl --
|
|
267
|
+
* Release resources associated with an element implementation record.
|
|
268
|
+
*/
|
|
269
|
+
static void FreeElementImpl(ElementImpl *elementImpl)
|
|
270
|
+
{
|
|
271
|
+
Tcl_HashSearch search;
|
|
272
|
+
Tcl_HashEntry *entryPtr;
|
|
273
|
+
int i;
|
|
274
|
+
|
|
275
|
+
/*
|
|
276
|
+
* Free default values:
|
|
277
|
+
*/
|
|
278
|
+
for (i = 0; i < elementImpl->nResources; ++i) {
|
|
279
|
+
if (elementImpl->defaultValues[i]) {
|
|
280
|
+
Tcl_DecrRefCount(elementImpl->defaultValues[i]);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
ckfree((ClientData)elementImpl->defaultValues);
|
|
284
|
+
|
|
285
|
+
/*
|
|
286
|
+
* Free option map cache:
|
|
287
|
+
*/
|
|
288
|
+
entryPtr = Tcl_FirstHashEntry(&elementImpl->optMapCache, &search);
|
|
289
|
+
while (entryPtr != NULL) {
|
|
290
|
+
ckfree(Tcl_GetHashValue(entryPtr));
|
|
291
|
+
entryPtr = Tcl_NextHashEntry(&search);
|
|
292
|
+
}
|
|
293
|
+
Tcl_DeleteHashTable(&elementImpl->optMapCache);
|
|
294
|
+
|
|
295
|
+
ckfree(elementImpl->elementRecord);
|
|
296
|
+
ckfree((ClientData)elementImpl);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
/*------------------------------------------------------------------------
|
|
301
|
+
* +++ Themes.
|
|
302
|
+
*/
|
|
303
|
+
|
|
304
|
+
static int ThemeEnabled(Ttk_Theme theme, void *clientData) { return 1; }
|
|
305
|
+
/* Default ThemeEnabledProc -- always return true */
|
|
306
|
+
|
|
307
|
+
typedef struct Ttk_Theme_
|
|
308
|
+
{
|
|
309
|
+
Ttk_Theme parentPtr; /* Parent theme. */
|
|
310
|
+
Tcl_HashTable elementTable; /* Map element names to ElementImpls */
|
|
311
|
+
Tcl_HashTable styleTable; /* Map style names to Styles */
|
|
312
|
+
Ttk_Style rootStyle; /* "." style, root of chain */
|
|
313
|
+
Ttk_ThemeEnabledProc *enabledProc; /* Function called by SetTheme */
|
|
314
|
+
void *enabledData; /* ClientData for enabledProc */
|
|
315
|
+
Ttk_ResourceCache cache; /* Back-pointer to resource cache */
|
|
316
|
+
} Theme;
|
|
317
|
+
|
|
318
|
+
static Theme *NewTheme(Ttk_ResourceCache cache, Ttk_Theme parent)
|
|
319
|
+
{
|
|
320
|
+
Theme *themePtr = (Theme*)ckalloc(sizeof(Theme));
|
|
321
|
+
Tcl_HashEntry *entryPtr;
|
|
322
|
+
int unused;
|
|
323
|
+
|
|
324
|
+
themePtr->parentPtr = parent;
|
|
325
|
+
themePtr->enabledProc = ThemeEnabled;
|
|
326
|
+
themePtr->enabledData = NULL;
|
|
327
|
+
themePtr->cache = cache;
|
|
328
|
+
Tcl_InitHashTable(&themePtr->elementTable, TCL_STRING_KEYS);
|
|
329
|
+
Tcl_InitHashTable(&themePtr->styleTable, TCL_STRING_KEYS);
|
|
330
|
+
|
|
331
|
+
/*
|
|
332
|
+
* Create root style "."
|
|
333
|
+
*/
|
|
334
|
+
entryPtr = Tcl_CreateHashEntry(&themePtr->styleTable, ".", &unused);
|
|
335
|
+
themePtr->rootStyle = NewStyle();
|
|
336
|
+
themePtr->rootStyle->styleName =
|
|
337
|
+
Tcl_GetHashKey(&themePtr->styleTable, entryPtr);
|
|
338
|
+
themePtr->rootStyle->cache = themePtr->cache;
|
|
339
|
+
Tcl_SetHashValue(entryPtr, (ClientData)themePtr->rootStyle);
|
|
340
|
+
|
|
341
|
+
return themePtr;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
static void FreeTheme(Theme *themePtr)
|
|
345
|
+
{
|
|
346
|
+
Tcl_HashSearch search;
|
|
347
|
+
Tcl_HashEntry *entryPtr;
|
|
348
|
+
|
|
349
|
+
/*
|
|
350
|
+
* Free associated ElementImpl's
|
|
351
|
+
*/
|
|
352
|
+
entryPtr = Tcl_FirstHashEntry(&themePtr->elementTable, &search);
|
|
353
|
+
while (entryPtr != NULL) {
|
|
354
|
+
ElementImpl *elementImpl = (ElementImpl *)Tcl_GetHashValue(entryPtr);
|
|
355
|
+
FreeElementImpl(elementImpl);
|
|
356
|
+
entryPtr = Tcl_NextHashEntry(&search);
|
|
357
|
+
}
|
|
358
|
+
Tcl_DeleteHashTable(&themePtr->elementTable);
|
|
359
|
+
|
|
360
|
+
/*
|
|
361
|
+
* Free style table:
|
|
362
|
+
*/
|
|
363
|
+
entryPtr = Tcl_FirstHashEntry(&themePtr->styleTable, &search);
|
|
364
|
+
while (entryPtr != NULL) {
|
|
365
|
+
Style *stylePtr = (Style*)Tcl_GetHashValue(entryPtr);
|
|
366
|
+
FreeStyle(stylePtr);
|
|
367
|
+
entryPtr = Tcl_NextHashEntry(&search);
|
|
368
|
+
}
|
|
369
|
+
Tcl_DeleteHashTable(&themePtr->styleTable);
|
|
370
|
+
|
|
371
|
+
/*
|
|
372
|
+
* Free theme record:
|
|
373
|
+
*/
|
|
374
|
+
ckfree((char *)themePtr);
|
|
375
|
+
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/*
|
|
380
|
+
* Element constructors.
|
|
381
|
+
*/
|
|
382
|
+
typedef struct {
|
|
383
|
+
Ttk_ElementFactory factory;
|
|
384
|
+
void *clientData;
|
|
385
|
+
} FactoryRec;
|
|
386
|
+
|
|
387
|
+
/*
|
|
388
|
+
* Cleanup records:
|
|
389
|
+
*/
|
|
390
|
+
typedef struct CleanupStruct {
|
|
391
|
+
void *clientData;
|
|
392
|
+
Ttk_CleanupProc *cleanupProc;
|
|
393
|
+
struct CleanupStruct *next;
|
|
394
|
+
} Cleanup;
|
|
395
|
+
|
|
396
|
+
/*------------------------------------------------------------------------
|
|
397
|
+
* +++ Master style package data structure.
|
|
398
|
+
*/
|
|
399
|
+
typedef struct
|
|
400
|
+
{
|
|
401
|
+
Tcl_Interp *interp; /* Owner interp */
|
|
402
|
+
Tcl_HashTable themeTable; /* KEY: name; VALUE: Theme pointer */
|
|
403
|
+
Tcl_HashTable factoryTable; /* KEY: name; VALUE: FactoryRec ptr */
|
|
404
|
+
Theme *defaultTheme; /* Default theme; global fallback*/
|
|
405
|
+
Theme *currentTheme; /* Currently-selected theme */
|
|
406
|
+
Cleanup *cleanupList; /* Cleanup records */
|
|
407
|
+
Ttk_ResourceCache cache; /* Resource cache */
|
|
408
|
+
int themeChangePending; /* scheduled ThemeChangedProc call? */
|
|
409
|
+
} StylePackageData;
|
|
410
|
+
|
|
411
|
+
static void ThemeChangedProc(ClientData); /* Forward */
|
|
412
|
+
|
|
413
|
+
/* Ttk_StylePkgFree --
|
|
414
|
+
* Cleanup procedure for StylePackageData.
|
|
415
|
+
*/
|
|
416
|
+
static void Ttk_StylePkgFree(ClientData clientData, Tcl_Interp *interp)
|
|
417
|
+
{
|
|
418
|
+
StylePackageData *pkgPtr = (StylePackageData *)clientData;
|
|
419
|
+
Tcl_HashSearch search;
|
|
420
|
+
Tcl_HashEntry *entryPtr;
|
|
421
|
+
Theme *themePtr;
|
|
422
|
+
Cleanup *cleanup;
|
|
423
|
+
|
|
424
|
+
/*
|
|
425
|
+
* Cancel any pending ThemeChanged calls:
|
|
426
|
+
*/
|
|
427
|
+
if (pkgPtr->themeChangePending) {
|
|
428
|
+
Tcl_CancelIdleCall(ThemeChangedProc, pkgPtr);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/*
|
|
432
|
+
* Free themes.
|
|
433
|
+
*/
|
|
434
|
+
entryPtr = Tcl_FirstHashEntry(&pkgPtr->themeTable, &search);
|
|
435
|
+
while (entryPtr != NULL) {
|
|
436
|
+
themePtr = (Theme *) Tcl_GetHashValue(entryPtr);
|
|
437
|
+
FreeTheme(themePtr);
|
|
438
|
+
entryPtr = Tcl_NextHashEntry(&search);
|
|
439
|
+
}
|
|
440
|
+
Tcl_DeleteHashTable(&pkgPtr->themeTable);
|
|
441
|
+
|
|
442
|
+
/*
|
|
443
|
+
* Free element constructor table:
|
|
444
|
+
*/
|
|
445
|
+
entryPtr = Tcl_FirstHashEntry(&pkgPtr->factoryTable, &search);
|
|
446
|
+
while (entryPtr != NULL) {
|
|
447
|
+
ckfree(Tcl_GetHashValue(entryPtr));
|
|
448
|
+
entryPtr = Tcl_NextHashEntry(&search);
|
|
449
|
+
}
|
|
450
|
+
Tcl_DeleteHashTable(&pkgPtr->factoryTable);
|
|
451
|
+
|
|
452
|
+
/*
|
|
453
|
+
* Release cache:
|
|
454
|
+
*/
|
|
455
|
+
Ttk_FreeResourceCache(pkgPtr->cache);
|
|
456
|
+
|
|
457
|
+
/*
|
|
458
|
+
* Call all registered cleanup procedures:
|
|
459
|
+
*/
|
|
460
|
+
cleanup = pkgPtr->cleanupList;
|
|
461
|
+
while (cleanup) {
|
|
462
|
+
Cleanup *next = cleanup->next;
|
|
463
|
+
cleanup->cleanupProc(cleanup->clientData);
|
|
464
|
+
ckfree((ClientData)cleanup);
|
|
465
|
+
cleanup = next;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
ckfree((char*)pkgPtr);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/*
|
|
472
|
+
* GetStylePackageData --
|
|
473
|
+
* Look up the package data registered with the interp.
|
|
474
|
+
*/
|
|
475
|
+
|
|
476
|
+
static StylePackageData *GetStylePackageData(Tcl_Interp *interp)
|
|
477
|
+
{
|
|
478
|
+
return (StylePackageData*)Tcl_GetAssocData(interp, "StylePackage", NULL);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/*
|
|
482
|
+
* Ttk_RegisterCleanup --
|
|
483
|
+
*
|
|
484
|
+
* Register a function to be called when a theme engine is deleted.
|
|
485
|
+
* (This only happens when the main interp is destroyed). The cleanup
|
|
486
|
+
* function is called with the current Tcl interpreter and the client
|
|
487
|
+
* data provided here.
|
|
488
|
+
*
|
|
489
|
+
*/
|
|
490
|
+
void Ttk_RegisterCleanup(
|
|
491
|
+
Tcl_Interp *interp, ClientData clientData, Ttk_CleanupProc *cleanupProc)
|
|
492
|
+
{
|
|
493
|
+
StylePackageData *pkgPtr = GetStylePackageData(interp);
|
|
494
|
+
Cleanup *cleanup = (Cleanup*)ckalloc(sizeof(*cleanup));
|
|
495
|
+
|
|
496
|
+
cleanup->clientData = clientData;
|
|
497
|
+
cleanup->cleanupProc = cleanupProc;
|
|
498
|
+
cleanup->next = pkgPtr->cleanupList;
|
|
499
|
+
pkgPtr->cleanupList = cleanup;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/* ThemeChangedProc --
|
|
503
|
+
* Notify all widgets that the theme has been changed.
|
|
504
|
+
* Scheduled as an idle callback; clientData is a StylePackageData *.
|
|
505
|
+
*
|
|
506
|
+
* Sends a <<ThemeChanged>> event to every widget in the hierarchy.
|
|
507
|
+
* Widgets respond to this by calling the WorldChanged class proc,
|
|
508
|
+
* which in turn recreates the layout.
|
|
509
|
+
*
|
|
510
|
+
* The Tk C API doesn't doesn't provide an easy way to traverse
|
|
511
|
+
* the widget hierarchy, so this is done by evaluating a Tcl script.
|
|
512
|
+
*/
|
|
513
|
+
|
|
514
|
+
static void ThemeChangedProc(ClientData clientData)
|
|
515
|
+
{
|
|
516
|
+
static char ThemeChangedScript[] = "ttk::ThemeChanged";
|
|
517
|
+
StylePackageData *pkgPtr = (StylePackageData *)clientData;
|
|
518
|
+
|
|
519
|
+
if (Tcl_GlobalEval(pkgPtr->interp, ThemeChangedScript) != TCL_OK) {
|
|
520
|
+
Tcl_BackgroundError(pkgPtr->interp);
|
|
521
|
+
}
|
|
522
|
+
pkgPtr->themeChangePending = 0;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/*
|
|
526
|
+
* ThemeChanged --
|
|
527
|
+
* Schedule a call to ThemeChanged if one is not already pending.
|
|
528
|
+
*/
|
|
529
|
+
static void ThemeChanged(StylePackageData *pkgPtr)
|
|
530
|
+
{
|
|
531
|
+
if (!pkgPtr->themeChangePending) {
|
|
532
|
+
Tcl_DoWhenIdle(ThemeChangedProc, pkgPtr);
|
|
533
|
+
pkgPtr->themeChangePending = 1;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/*
|
|
538
|
+
* Ttk_CreateTheme --
|
|
539
|
+
* Create a new theme and register it in the global theme table.
|
|
540
|
+
*
|
|
541
|
+
* Returns:
|
|
542
|
+
* Pointer to new Theme structure; NULL if named theme already exists.
|
|
543
|
+
* Leaves an error message in interp's result on error.
|
|
544
|
+
*/
|
|
545
|
+
|
|
546
|
+
Ttk_Theme
|
|
547
|
+
Ttk_CreateTheme(
|
|
548
|
+
Tcl_Interp *interp, /* Interpreter in which to create theme */
|
|
549
|
+
const char *name, /* Name of the theme to create. */
|
|
550
|
+
Ttk_Theme parent) /* Parent/fallback theme, NULL for default */
|
|
551
|
+
{
|
|
552
|
+
StylePackageData *pkgPtr = GetStylePackageData(interp);
|
|
553
|
+
Tcl_HashEntry *entryPtr;
|
|
554
|
+
int newEntry;
|
|
555
|
+
Theme *themePtr;
|
|
556
|
+
|
|
557
|
+
entryPtr = Tcl_CreateHashEntry(&pkgPtr->themeTable, name, &newEntry);
|
|
558
|
+
if (!newEntry) {
|
|
559
|
+
Tcl_ResetResult(interp);
|
|
560
|
+
Tcl_AppendResult(interp, "Theme ", name, " already exists", NULL);
|
|
561
|
+
return NULL;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/*
|
|
565
|
+
* Initialize new theme:
|
|
566
|
+
*/
|
|
567
|
+
if (!parent) parent = pkgPtr->defaultTheme;
|
|
568
|
+
|
|
569
|
+
themePtr = NewTheme(pkgPtr->cache, parent);
|
|
570
|
+
Tcl_SetHashValue(entryPtr, (ClientData) themePtr);
|
|
571
|
+
|
|
572
|
+
return themePtr;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
/*
|
|
577
|
+
* Ttk_SetThemeEnabledProc --
|
|
578
|
+
* Sets a procedure that is used to check that this theme is available.
|
|
579
|
+
*/
|
|
580
|
+
|
|
581
|
+
void Ttk_SetThemeEnabledProc(
|
|
582
|
+
Ttk_Theme theme, Ttk_ThemeEnabledProc enabledProc, void *enabledData)
|
|
583
|
+
{
|
|
584
|
+
theme->enabledProc = enabledProc;
|
|
585
|
+
theme->enabledData = enabledData;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
/*
|
|
589
|
+
* LookupTheme --
|
|
590
|
+
* Retrieve a registered theme by name. If not found,
|
|
591
|
+
* returns NULL and leaves an error message in interp's result.
|
|
592
|
+
*/
|
|
593
|
+
|
|
594
|
+
static Ttk_Theme LookupTheme(
|
|
595
|
+
Tcl_Interp *interp, /* where to leave error messages */
|
|
596
|
+
StylePackageData *pkgPtr, /* style package master record */
|
|
597
|
+
const char *name) /* theme name */
|
|
598
|
+
{
|
|
599
|
+
Tcl_HashEntry *entryPtr;
|
|
600
|
+
|
|
601
|
+
entryPtr = Tcl_FindHashEntry(&pkgPtr->themeTable, name);
|
|
602
|
+
if (!entryPtr) {
|
|
603
|
+
Tcl_ResetResult(interp);
|
|
604
|
+
Tcl_AppendResult(interp, "theme \"", name, "\" doesn't exist", NULL);
|
|
605
|
+
return NULL;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
return (Ttk_Theme)Tcl_GetHashValue(entryPtr);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/*
|
|
612
|
+
* Ttk_GetTheme --
|
|
613
|
+
* Public interface to LookupTheme.
|
|
614
|
+
*/
|
|
615
|
+
Ttk_Theme Ttk_GetTheme(Tcl_Interp *interp, const char *themeName)
|
|
616
|
+
{
|
|
617
|
+
StylePackageData *pkgPtr = GetStylePackageData(interp);
|
|
618
|
+
|
|
619
|
+
return LookupTheme(interp, pkgPtr, themeName);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
Ttk_Theme Ttk_GetCurrentTheme(Tcl_Interp *interp)
|
|
623
|
+
{
|
|
624
|
+
StylePackageData *pkgPtr = GetStylePackageData(interp);
|
|
625
|
+
return pkgPtr->currentTheme;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
Ttk_Theme Ttk_GetDefaultTheme(Tcl_Interp *interp)
|
|
629
|
+
{
|
|
630
|
+
StylePackageData *pkgPtr = GetStylePackageData(interp);
|
|
631
|
+
return pkgPtr->defaultTheme;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/*
|
|
635
|
+
* Ttk_UseTheme --
|
|
636
|
+
* Set the current theme, notify all widgets that the theme has changed.
|
|
637
|
+
*/
|
|
638
|
+
int Ttk_UseTheme(Tcl_Interp *interp, Ttk_Theme theme)
|
|
639
|
+
{
|
|
640
|
+
StylePackageData *pkgPtr = GetStylePackageData(interp);
|
|
641
|
+
|
|
642
|
+
/*
|
|
643
|
+
* Check if selected theme is enabled:
|
|
644
|
+
*/
|
|
645
|
+
while (theme && !theme->enabledProc(theme, theme->enabledData)) {
|
|
646
|
+
theme = theme->parentPtr;
|
|
647
|
+
}
|
|
648
|
+
if (!theme) {
|
|
649
|
+
/* This shouldn't happen -- default theme should always work */
|
|
650
|
+
Tcl_Panic("No themes available?");
|
|
651
|
+
return TCL_ERROR;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
pkgPtr->currentTheme = theme;
|
|
655
|
+
ThemeChanged(pkgPtr);
|
|
656
|
+
return TCL_OK;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/*
|
|
660
|
+
* Ttk_GetResourceCache --
|
|
661
|
+
* Return the resource cache associated with 'interp'
|
|
662
|
+
*/
|
|
663
|
+
Ttk_ResourceCache
|
|
664
|
+
Ttk_GetResourceCache(Tcl_Interp *interp)
|
|
665
|
+
{
|
|
666
|
+
StylePackageData *pkgPtr = GetStylePackageData(interp);
|
|
667
|
+
return pkgPtr->cache;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/*
|
|
671
|
+
* Register a new layout specification with a style.
|
|
672
|
+
* @@@ TODO: Make sure layoutName is not ".", root style must not have a layout
|
|
673
|
+
*/
|
|
674
|
+
MODULE_SCOPE
|
|
675
|
+
void Ttk_RegisterLayoutTemplate(
|
|
676
|
+
Ttk_Theme theme, /* Target theme */
|
|
677
|
+
const char *layoutName, /* Name of new layout */
|
|
678
|
+
Ttk_LayoutTemplate layoutTemplate) /* Template */
|
|
679
|
+
{
|
|
680
|
+
Ttk_Style style = Ttk_GetStyle(theme, layoutName);
|
|
681
|
+
if (style->layoutTemplate) {
|
|
682
|
+
Ttk_FreeLayoutTemplate(style->layoutTemplate);
|
|
683
|
+
}
|
|
684
|
+
style->layoutTemplate = layoutTemplate;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
void Ttk_RegisterLayout(
|
|
688
|
+
Ttk_Theme themePtr, /* Target theme */
|
|
689
|
+
const char *layoutName, /* Name of new layout */
|
|
690
|
+
Ttk_LayoutSpec specPtr) /* Static layout information */
|
|
691
|
+
{
|
|
692
|
+
Ttk_LayoutTemplate layoutTemplate = Ttk_BuildLayoutTemplate(specPtr);
|
|
693
|
+
Ttk_RegisterLayoutTemplate(themePtr, layoutName, layoutTemplate);
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/*
|
|
697
|
+
* Ttk_GetStyle --
|
|
698
|
+
* Look up a Style from a Theme, create new style if not found.
|
|
699
|
+
*/
|
|
700
|
+
Ttk_Style Ttk_GetStyle(Ttk_Theme themePtr, const char *styleName)
|
|
701
|
+
{
|
|
702
|
+
Tcl_HashEntry *entryPtr;
|
|
703
|
+
int newStyle;
|
|
704
|
+
|
|
705
|
+
entryPtr = Tcl_CreateHashEntry(&themePtr->styleTable, styleName, &newStyle);
|
|
706
|
+
if (newStyle) {
|
|
707
|
+
Ttk_Style stylePtr = NewStyle();
|
|
708
|
+
const char *dot = strchr(styleName, '.');
|
|
709
|
+
|
|
710
|
+
if (dot) {
|
|
711
|
+
stylePtr->parentStyle = Ttk_GetStyle(themePtr, dot + 1);
|
|
712
|
+
} else {
|
|
713
|
+
stylePtr->parentStyle = themePtr->rootStyle;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
stylePtr->styleName = Tcl_GetHashKey(&themePtr->styleTable, entryPtr);
|
|
717
|
+
stylePtr->cache = stylePtr->parentStyle->cache;
|
|
718
|
+
Tcl_SetHashValue(entryPtr, (ClientData)stylePtr);
|
|
719
|
+
return stylePtr;
|
|
720
|
+
}
|
|
721
|
+
return (Style*)Tcl_GetHashValue(entryPtr);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/* FindLayoutTemplate --
|
|
725
|
+
* Locate a layout template in the layout table, checking
|
|
726
|
+
* generic names to specific names first, then looking for
|
|
727
|
+
* the full name in the parent theme.
|
|
728
|
+
*/
|
|
729
|
+
Ttk_LayoutTemplate
|
|
730
|
+
Ttk_FindLayoutTemplate(Ttk_Theme themePtr, const char *layoutName)
|
|
731
|
+
{
|
|
732
|
+
while (themePtr) {
|
|
733
|
+
Ttk_Style stylePtr = Ttk_GetStyle(themePtr, layoutName);
|
|
734
|
+
while (stylePtr) {
|
|
735
|
+
if (stylePtr->layoutTemplate) {
|
|
736
|
+
return stylePtr->layoutTemplate;
|
|
737
|
+
}
|
|
738
|
+
stylePtr = stylePtr->parentStyle;
|
|
739
|
+
}
|
|
740
|
+
themePtr = themePtr->parentPtr;
|
|
741
|
+
}
|
|
742
|
+
return NULL;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
const char *Ttk_StyleName(Ttk_Style stylePtr)
|
|
746
|
+
{
|
|
747
|
+
return stylePtr->styleName;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
/*
|
|
751
|
+
* Ttk_GetElement --
|
|
752
|
+
* Look up an element implementation by name in a given theme.
|
|
753
|
+
* If not found, try generic element names in this theme, then
|
|
754
|
+
* repeat the lookups in the parent theme.
|
|
755
|
+
* If not found, return the null element.
|
|
756
|
+
*/
|
|
757
|
+
Ttk_ElementImpl Ttk_GetElement(Ttk_Theme themePtr, const char *elementName)
|
|
758
|
+
{
|
|
759
|
+
Tcl_HashEntry *entryPtr;
|
|
760
|
+
const char *dot = elementName;
|
|
761
|
+
|
|
762
|
+
/*
|
|
763
|
+
* Check if element has already been registered:
|
|
764
|
+
*/
|
|
765
|
+
entryPtr = Tcl_FindHashEntry(&themePtr->elementTable, elementName);
|
|
766
|
+
if (entryPtr) {
|
|
767
|
+
return (Ttk_ElementImpl)Tcl_GetHashValue(entryPtr);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
/*
|
|
771
|
+
* Check generic names:
|
|
772
|
+
*/
|
|
773
|
+
while (!entryPtr && ((dot = strchr(dot, '.')) != NULL)) {
|
|
774
|
+
dot++;
|
|
775
|
+
entryPtr = Tcl_FindHashEntry(&themePtr->elementTable, dot);
|
|
776
|
+
}
|
|
777
|
+
if (entryPtr) {
|
|
778
|
+
return (ElementImpl *)Tcl_GetHashValue(entryPtr);
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
/*
|
|
782
|
+
* Check parent theme:
|
|
783
|
+
*/
|
|
784
|
+
if (themePtr->parentPtr) {
|
|
785
|
+
return Ttk_GetElement(themePtr->parentPtr, elementName);
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
/*
|
|
789
|
+
* Not found, and this is the root theme; return null element, "".
|
|
790
|
+
* (@@@ SHOULD: signal a background error)
|
|
791
|
+
*/
|
|
792
|
+
entryPtr = Tcl_FindHashEntry(&themePtr->elementTable, "");
|
|
793
|
+
/* ASSERT: entryPtr != 0 */
|
|
794
|
+
return (Ttk_ElementImpl)Tcl_GetHashValue(entryPtr);
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
const char *Ttk_ElementName(ElementImpl *elementImpl)
|
|
798
|
+
{
|
|
799
|
+
return elementImpl->name;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
/*
|
|
803
|
+
* Ttk_RegisterElementFactory --
|
|
804
|
+
* Register a new element factory.
|
|
805
|
+
*/
|
|
806
|
+
int Ttk_RegisterElementFactory(
|
|
807
|
+
Tcl_Interp *interp, const char *name,
|
|
808
|
+
Ttk_ElementFactory factory, void *clientData)
|
|
809
|
+
{
|
|
810
|
+
StylePackageData *pkgPtr = GetStylePackageData(interp);
|
|
811
|
+
FactoryRec *recPtr = (FactoryRec*)ckalloc(sizeof(*recPtr));
|
|
812
|
+
Tcl_HashEntry *entryPtr;
|
|
813
|
+
int newEntry;
|
|
814
|
+
|
|
815
|
+
recPtr->factory = factory;
|
|
816
|
+
recPtr->clientData = clientData;
|
|
817
|
+
|
|
818
|
+
entryPtr = Tcl_CreateHashEntry(&pkgPtr->factoryTable, name, &newEntry);
|
|
819
|
+
if (!newEntry) {
|
|
820
|
+
/* Free old factory: */
|
|
821
|
+
ckfree(Tcl_GetHashValue(entryPtr));
|
|
822
|
+
}
|
|
823
|
+
Tcl_SetHashValue(entryPtr, recPtr);
|
|
824
|
+
|
|
825
|
+
return TCL_OK;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
|
|
829
|
+
/* Ttk_CloneElement -- element factory procedure.
|
|
830
|
+
* (style element create $name) "from" $theme ?$element?
|
|
831
|
+
*/
|
|
832
|
+
static int Ttk_CloneElement(
|
|
833
|
+
Tcl_Interp *interp, void *clientData,
|
|
834
|
+
Ttk_Theme theme, const char *elementName,
|
|
835
|
+
int objc, Tcl_Obj *CONST objv[])
|
|
836
|
+
{
|
|
837
|
+
Ttk_Theme fromTheme;
|
|
838
|
+
ElementImpl *fromElement;
|
|
839
|
+
|
|
840
|
+
if (objc <= 0 || objc > 2) {
|
|
841
|
+
Tcl_WrongNumArgs(interp, 0, objv, "theme ?element?");
|
|
842
|
+
return TCL_ERROR;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
fromTheme = Ttk_GetTheme(interp, Tcl_GetString(objv[0]));
|
|
846
|
+
if (!fromTheme) {
|
|
847
|
+
return TCL_ERROR;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
if (objc == 2) {
|
|
851
|
+
fromElement = Ttk_GetElement(fromTheme, Tcl_GetString(objv[1]));
|
|
852
|
+
} else {
|
|
853
|
+
fromElement = Ttk_GetElement(fromTheme, elementName);
|
|
854
|
+
}
|
|
855
|
+
if (!fromElement) {
|
|
856
|
+
return TCL_ERROR;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
if (Ttk_RegisterElement(interp, theme, elementName,
|
|
860
|
+
fromElement->specPtr, fromElement->clientData) == NULL)
|
|
861
|
+
{
|
|
862
|
+
return TCL_ERROR;
|
|
863
|
+
}
|
|
864
|
+
return TCL_OK;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
/* Ttk_RegisterElement--
|
|
868
|
+
* Register an element in the given theme.
|
|
869
|
+
* Returns: Element handle if successful, NULL otherwise.
|
|
870
|
+
* On failure, leaves an error message in interp's result
|
|
871
|
+
* if interp is non-NULL.
|
|
872
|
+
*/
|
|
873
|
+
|
|
874
|
+
Ttk_ElementImpl Ttk_RegisterElement(
|
|
875
|
+
Tcl_Interp *interp, /* Where to leave error messages */
|
|
876
|
+
Ttk_Theme theme, /* Style engine providing the implementation. */
|
|
877
|
+
const char *name, /* Name of new element */
|
|
878
|
+
Ttk_ElementSpec *specPtr, /* Static template information */
|
|
879
|
+
void *clientData) /* application-specific data */
|
|
880
|
+
{
|
|
881
|
+
ElementImpl *elementImpl;
|
|
882
|
+
Tcl_HashEntry *entryPtr;
|
|
883
|
+
int newEntry;
|
|
884
|
+
|
|
885
|
+
if (specPtr->version != TK_STYLE_VERSION_2) {
|
|
886
|
+
/* Version mismatch */
|
|
887
|
+
if (interp) {
|
|
888
|
+
Tcl_ResetResult(interp);
|
|
889
|
+
Tcl_AppendResult(interp, "Internal error: Ttk_RegisterElement (",
|
|
890
|
+
name, "): invalid version",
|
|
891
|
+
NULL);
|
|
892
|
+
}
|
|
893
|
+
return 0;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
entryPtr = Tcl_CreateHashEntry(&theme->elementTable, name, &newEntry);
|
|
897
|
+
if (!newEntry) {
|
|
898
|
+
if (interp) {
|
|
899
|
+
Tcl_ResetResult(interp);
|
|
900
|
+
Tcl_AppendResult(interp, "Duplicate element ", name, NULL);
|
|
901
|
+
}
|
|
902
|
+
return 0;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
name = Tcl_GetHashKey(&theme->elementTable, entryPtr);
|
|
906
|
+
elementImpl = NewElementImpl(name, specPtr, clientData);
|
|
907
|
+
Tcl_SetHashValue(entryPtr, elementImpl);
|
|
908
|
+
|
|
909
|
+
return elementImpl;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
/* Ttk_RegisterElementSpec (deprecated) --
|
|
913
|
+
* Register a new element.
|
|
914
|
+
*/
|
|
915
|
+
int Ttk_RegisterElementSpec(Ttk_Theme theme,
|
|
916
|
+
const char *name, Ttk_ElementSpec *specPtr, void *clientData)
|
|
917
|
+
{
|
|
918
|
+
return Ttk_RegisterElement(NULL, theme, name, specPtr, clientData)
|
|
919
|
+
? TCL_OK : TCL_ERROR;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
/*------------------------------------------------------------------------
|
|
923
|
+
* +++ Element record initialization.
|
|
924
|
+
*/
|
|
925
|
+
|
|
926
|
+
/*
|
|
927
|
+
* AllocateResource --
|
|
928
|
+
* Extra initialization for element options like TK_OPTION_COLOR, etc.
|
|
929
|
+
*
|
|
930
|
+
* Returns: 1 if OK, 0 on failure.
|
|
931
|
+
*
|
|
932
|
+
* Note: if resource allocation fails at this point (just prior
|
|
933
|
+
* to drawing an element), there's really no good place to
|
|
934
|
+
* report the error. Instead we just silently fail.
|
|
935
|
+
*/
|
|
936
|
+
|
|
937
|
+
static int AllocateResource(
|
|
938
|
+
Ttk_ResourceCache cache,
|
|
939
|
+
Tk_Window tkwin,
|
|
940
|
+
Tcl_Obj **destPtr,
|
|
941
|
+
int optionType)
|
|
942
|
+
{
|
|
943
|
+
Tcl_Obj *resource = *destPtr;
|
|
944
|
+
|
|
945
|
+
switch (optionType)
|
|
946
|
+
{
|
|
947
|
+
case TK_OPTION_FONT:
|
|
948
|
+
return (*destPtr = Ttk_UseFont(cache, tkwin, resource)) != NULL;
|
|
949
|
+
case TK_OPTION_COLOR:
|
|
950
|
+
return (*destPtr = Ttk_UseColor(cache, tkwin, resource)) != NULL;
|
|
951
|
+
case TK_OPTION_BORDER:
|
|
952
|
+
return (*destPtr = Ttk_UseBorder(cache, tkwin, resource)) != NULL;
|
|
953
|
+
default:
|
|
954
|
+
/* no-op; always succeeds */
|
|
955
|
+
return 1;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
/*
|
|
960
|
+
* InitializeElementRecord --
|
|
961
|
+
*
|
|
962
|
+
* Fill in the element record based on the element's option table.
|
|
963
|
+
* Resources are initialized from:
|
|
964
|
+
* the corresponding widget option if present and non-NULL,
|
|
965
|
+
* otherwise the dynamic state map if specified,
|
|
966
|
+
* otherwise from the corresponding widget resource if present,
|
|
967
|
+
* otherwise the default value specified at registration time.
|
|
968
|
+
*
|
|
969
|
+
* Returns:
|
|
970
|
+
* 1 if OK, 0 if an error is detected.
|
|
971
|
+
*
|
|
972
|
+
* NOTES:
|
|
973
|
+
* Tcl_Obj * reference counts are _NOT_ adjusted.
|
|
974
|
+
*/
|
|
975
|
+
|
|
976
|
+
static
|
|
977
|
+
int InitializeElementRecord(
|
|
978
|
+
ElementImpl *element, /* Element instance to initialize */
|
|
979
|
+
Ttk_Style style, /* Style table */
|
|
980
|
+
char *widgetRecord, /* Source of widget option values */
|
|
981
|
+
Tk_OptionTable optionTable, /* Option table describing widget record */
|
|
982
|
+
Tk_Window tkwin, /* Corresponding window */
|
|
983
|
+
Ttk_State state) /* Widget or element state */
|
|
984
|
+
{
|
|
985
|
+
char *elementRecord = element->elementRecord;
|
|
986
|
+
OptionMap optionMap = GetOptionMap(element,optionTable);
|
|
987
|
+
int nResources = element->nResources;
|
|
988
|
+
Ttk_ResourceCache cache = style->cache;
|
|
989
|
+
Ttk_ElementOptionSpec *elementOption = element->specPtr->options;
|
|
990
|
+
|
|
991
|
+
int i;
|
|
992
|
+
for (i=0; i<nResources; ++i, ++elementOption) {
|
|
993
|
+
Tcl_Obj **dest = (Tcl_Obj **)
|
|
994
|
+
(elementRecord + elementOption->offset);
|
|
995
|
+
const char *optionName = elementOption->optionName;
|
|
996
|
+
Tcl_Obj *stateMap = LookupStateMap(style, optionName);
|
|
997
|
+
Tcl_Obj *dynamicSetting = 0;
|
|
998
|
+
Tcl_Obj *widgetValue = 0;
|
|
999
|
+
Tcl_Obj *elementDefault = element->defaultValues[i];
|
|
1000
|
+
|
|
1001
|
+
if (stateMap) {
|
|
1002
|
+
dynamicSetting = Ttk_StateMapLookup(NULL, stateMap, state);
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
if (optionMap[i]) {
|
|
1006
|
+
widgetValue = *(Tcl_Obj **)
|
|
1007
|
+
(widgetRecord + optionMap[i]->objOffset);
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
if (widgetValue) {
|
|
1011
|
+
*dest = widgetValue;
|
|
1012
|
+
} else if (dynamicSetting) {
|
|
1013
|
+
*dest = dynamicSetting;
|
|
1014
|
+
} else {
|
|
1015
|
+
Tcl_Obj *styleDefault = LookupDefault(style, optionName);
|
|
1016
|
+
*dest = styleDefault ? styleDefault : elementDefault;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
if (!AllocateResource(cache, tkwin, dest, elementOption->type)) {
|
|
1020
|
+
return 0;
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
return 1;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
/*------------------------------------------------------------------------
|
|
1028
|
+
* +++ Public API.
|
|
1029
|
+
*/
|
|
1030
|
+
|
|
1031
|
+
/*
|
|
1032
|
+
* Ttk_QueryStyle --
|
|
1033
|
+
* Look up a style option based on the current state.
|
|
1034
|
+
*/
|
|
1035
|
+
Tcl_Obj *Ttk_QueryStyle(
|
|
1036
|
+
Ttk_Style style, /* Style to query */
|
|
1037
|
+
void *recordPtr, /* Widget record */
|
|
1038
|
+
Tk_OptionTable optionTable, /* Option table describing widget record */
|
|
1039
|
+
const char *optionName, /* Option name */
|
|
1040
|
+
Ttk_State state) /* Current state */
|
|
1041
|
+
{
|
|
1042
|
+
Tcl_Obj *stateMap;
|
|
1043
|
+
const Tk_OptionSpec *optionSpec;
|
|
1044
|
+
Tcl_Obj *result;
|
|
1045
|
+
|
|
1046
|
+
/*
|
|
1047
|
+
* Check widget record:
|
|
1048
|
+
*/
|
|
1049
|
+
optionSpec = TTKGetOptionSpec(optionName, optionTable, TK_OPTION_ANY);
|
|
1050
|
+
if (optionSpec) {
|
|
1051
|
+
result = *(Tcl_Obj**)(((char*)recordPtr) + optionSpec->objOffset);
|
|
1052
|
+
if (result) {
|
|
1053
|
+
return result;
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
/*
|
|
1058
|
+
* Check dynamic settings:
|
|
1059
|
+
*/
|
|
1060
|
+
stateMap = LookupStateMap(style, optionName);
|
|
1061
|
+
if (stateMap) {
|
|
1062
|
+
result = Ttk_StateMapLookup(NULL, stateMap, state);
|
|
1063
|
+
if (result) {
|
|
1064
|
+
return result;
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
/*
|
|
1069
|
+
* Use style default:
|
|
1070
|
+
*/
|
|
1071
|
+
return LookupDefault(style, optionName);
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
/*
|
|
1075
|
+
* Ttk_ElementSize --
|
|
1076
|
+
* Compute the requested size of the given element.
|
|
1077
|
+
*/
|
|
1078
|
+
|
|
1079
|
+
void
|
|
1080
|
+
Ttk_ElementSize(
|
|
1081
|
+
ElementImpl *element, /* Element to query */
|
|
1082
|
+
Ttk_Style style, /* Style settings */
|
|
1083
|
+
char *recordPtr, /* The widget record. */
|
|
1084
|
+
Tk_OptionTable optionTable, /* Description of widget record */
|
|
1085
|
+
Tk_Window tkwin, /* The widget window. */
|
|
1086
|
+
Ttk_State state, /* Current widget state */
|
|
1087
|
+
int *widthPtr, /* Requested width */
|
|
1088
|
+
int *heightPtr, /* Reqested height */
|
|
1089
|
+
Ttk_Padding *paddingPtr) /* Requested inner border */
|
|
1090
|
+
{
|
|
1091
|
+
paddingPtr->left = paddingPtr->right = paddingPtr->top = paddingPtr->bottom
|
|
1092
|
+
= *widthPtr = *heightPtr = 0;
|
|
1093
|
+
|
|
1094
|
+
if (!InitializeElementRecord(element, style, recordPtr, optionTable, tkwin, state))
|
|
1095
|
+
return;
|
|
1096
|
+
element->specPtr->size(
|
|
1097
|
+
element->clientData, element->elementRecord,
|
|
1098
|
+
tkwin, widthPtr, heightPtr, paddingPtr);
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
/*
|
|
1102
|
+
* Ttk_DrawElement --
|
|
1103
|
+
* Draw the given widget element in a given drawable area.
|
|
1104
|
+
*/
|
|
1105
|
+
|
|
1106
|
+
void
|
|
1107
|
+
Ttk_DrawElement(
|
|
1108
|
+
ElementImpl *element, /* Element instance */
|
|
1109
|
+
Ttk_Style style, /* Style settings */
|
|
1110
|
+
char *recordPtr, /* The widget record. */
|
|
1111
|
+
Tk_OptionTable optionTable, /* Description of option table */
|
|
1112
|
+
Tk_Window tkwin, /* The widget window. */
|
|
1113
|
+
Drawable d, /* Where to draw element. */
|
|
1114
|
+
Ttk_Box b, /* Element area */
|
|
1115
|
+
Ttk_State state) /* Widget or element state flags. */
|
|
1116
|
+
{
|
|
1117
|
+
if (b.width <= 0 || b.height <= 0)
|
|
1118
|
+
return;
|
|
1119
|
+
if (!InitializeElementRecord(element, style, recordPtr, optionTable, tkwin, state))
|
|
1120
|
+
return;
|
|
1121
|
+
element->specPtr->draw(
|
|
1122
|
+
element->clientData, element->elementRecord,
|
|
1123
|
+
tkwin, d, b, state);
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
/*------------------------------------------------------------------------
|
|
1127
|
+
* +++ 'style' command ensemble procedures.
|
|
1128
|
+
*/
|
|
1129
|
+
|
|
1130
|
+
/*
|
|
1131
|
+
* EnumerateHashTable --
|
|
1132
|
+
* Helper routine. Sets interp's result to the list of all keys
|
|
1133
|
+
* in the hash table.
|
|
1134
|
+
*
|
|
1135
|
+
* Returns: TCL_OK.
|
|
1136
|
+
* Side effects: Sets interp's result.
|
|
1137
|
+
*/
|
|
1138
|
+
|
|
1139
|
+
static int EnumerateHashTable(Tcl_Interp *interp, Tcl_HashTable *ht)
|
|
1140
|
+
{
|
|
1141
|
+
Tcl_HashSearch search;
|
|
1142
|
+
Tcl_Obj *result = Tcl_NewListObj(0, NULL);
|
|
1143
|
+
Tcl_HashEntry *entryPtr = Tcl_FirstHashEntry(ht, &search);
|
|
1144
|
+
|
|
1145
|
+
while (entryPtr != NULL) {
|
|
1146
|
+
Tcl_Obj *nameObj = Tcl_NewStringObj(Tcl_GetHashKey(ht, entryPtr),-1);
|
|
1147
|
+
Tcl_ListObjAppendElement(interp, result, nameObj);
|
|
1148
|
+
entryPtr = Tcl_NextHashEntry(&search);
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
Tcl_SetObjResult(interp, result);
|
|
1152
|
+
return TCL_OK;
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
/* HashTableToDict --
|
|
1156
|
+
* Helper routine. Converts a TCL_STRING_KEYS Tcl_HashTable
|
|
1157
|
+
* with Tcl_Obj * entries into a dictionary.
|
|
1158
|
+
*/
|
|
1159
|
+
static Tcl_Obj* HashTableToDict(Tcl_HashTable *ht)
|
|
1160
|
+
{
|
|
1161
|
+
Tcl_HashSearch search;
|
|
1162
|
+
Tcl_Obj *result = Tcl_NewListObj(0, NULL);
|
|
1163
|
+
Tcl_HashEntry *entryPtr = Tcl_FirstHashEntry(ht, &search);
|
|
1164
|
+
|
|
1165
|
+
while (entryPtr != NULL) {
|
|
1166
|
+
Tcl_Obj *nameObj = Tcl_NewStringObj(Tcl_GetHashKey(ht, entryPtr),-1);
|
|
1167
|
+
Tcl_Obj *valueObj = (Tcl_Obj*)Tcl_GetHashValue(entryPtr);
|
|
1168
|
+
Tcl_ListObjAppendElement(NULL, result, nameObj);
|
|
1169
|
+
Tcl_ListObjAppendElement(NULL, result, valueObj);
|
|
1170
|
+
entryPtr = Tcl_NextHashEntry(&search);
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
return result;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
/* + style map $style ? -resource statemap ... ?
|
|
1177
|
+
*
|
|
1178
|
+
* Note that resource names are unconstrained; the Style
|
|
1179
|
+
* doesn't know what resources individual elements may use.
|
|
1180
|
+
*/
|
|
1181
|
+
static int
|
|
1182
|
+
StyleMapCmd(
|
|
1183
|
+
ClientData clientData, /* Master StylePackageData pointer */
|
|
1184
|
+
Tcl_Interp *interp, /* Current interpreter */
|
|
1185
|
+
int objc, /* Number of arguments */
|
|
1186
|
+
Tcl_Obj * CONST objv[]) /* Argument objects */
|
|
1187
|
+
{
|
|
1188
|
+
StylePackageData *pkgPtr = (StylePackageData *)clientData;
|
|
1189
|
+
Ttk_Theme theme = pkgPtr->currentTheme;
|
|
1190
|
+
const char *styleName;
|
|
1191
|
+
Style *stylePtr;
|
|
1192
|
+
int i;
|
|
1193
|
+
|
|
1194
|
+
if (objc < 3) {
|
|
1195
|
+
usage:
|
|
1196
|
+
Tcl_WrongNumArgs(interp,2,objv,"style ?-option ?value...??");
|
|
1197
|
+
return TCL_ERROR;
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
styleName = Tcl_GetString(objv[2]);
|
|
1201
|
+
stylePtr = Ttk_GetStyle(theme, styleName);
|
|
1202
|
+
|
|
1203
|
+
/* NOTE: StateMaps are actually Tcl_Obj *s, so HashTableToDict works
|
|
1204
|
+
* for settingsTable.
|
|
1205
|
+
*/
|
|
1206
|
+
if (objc == 3) { /* style map $styleName */
|
|
1207
|
+
Tcl_SetObjResult(interp, HashTableToDict(&stylePtr->settingsTable));
|
|
1208
|
+
return TCL_OK;
|
|
1209
|
+
} else if (objc == 4) { /* style map $styleName -option */
|
|
1210
|
+
const char *optionName = Tcl_GetString(objv[3]);
|
|
1211
|
+
Tcl_HashEntry *entryPtr =
|
|
1212
|
+
Tcl_FindHashEntry(&stylePtr->settingsTable, optionName);
|
|
1213
|
+
if (entryPtr) {
|
|
1214
|
+
Tcl_SetObjResult(interp, (Tcl_Obj*)Tcl_GetHashValue(entryPtr));
|
|
1215
|
+
}
|
|
1216
|
+
return TCL_OK;
|
|
1217
|
+
} else if (objc % 2 != 1) {
|
|
1218
|
+
goto usage;
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
for (i = 3; i < objc; i += 2) {
|
|
1222
|
+
const char *optionName = Tcl_GetString(objv[i]);
|
|
1223
|
+
Tcl_Obj *stateMap = objv[i+1];
|
|
1224
|
+
Tcl_HashEntry *entryPtr;
|
|
1225
|
+
int newEntry;
|
|
1226
|
+
|
|
1227
|
+
/* Make sure 'stateMap' is legal:
|
|
1228
|
+
* (@@@ SHOULD: check for valid resource values as well,
|
|
1229
|
+
* but we don't know what types they should be at this level.)
|
|
1230
|
+
*/
|
|
1231
|
+
if (!Ttk_GetStateMapFromObj(interp, stateMap))
|
|
1232
|
+
return TCL_ERROR;
|
|
1233
|
+
|
|
1234
|
+
entryPtr = Tcl_CreateHashEntry(
|
|
1235
|
+
&stylePtr->settingsTable,optionName,&newEntry);
|
|
1236
|
+
|
|
1237
|
+
Tcl_IncrRefCount(stateMap);
|
|
1238
|
+
if (!newEntry) {
|
|
1239
|
+
Tcl_DecrRefCount((Tcl_Obj*)Tcl_GetHashValue(entryPtr));
|
|
1240
|
+
}
|
|
1241
|
+
Tcl_SetHashValue(entryPtr, stateMap);
|
|
1242
|
+
}
|
|
1243
|
+
ThemeChanged(pkgPtr);
|
|
1244
|
+
return TCL_OK;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
/* + style configure $style -option ?value...
|
|
1248
|
+
*/
|
|
1249
|
+
static int StyleConfigureCmd(
|
|
1250
|
+
ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[])
|
|
1251
|
+
{
|
|
1252
|
+
StylePackageData *pkgPtr = (StylePackageData *)clientData;
|
|
1253
|
+
Ttk_Theme theme = pkgPtr->currentTheme;
|
|
1254
|
+
const char *styleName;
|
|
1255
|
+
Style *stylePtr;
|
|
1256
|
+
int i;
|
|
1257
|
+
|
|
1258
|
+
if (objc < 3) {
|
|
1259
|
+
usage:
|
|
1260
|
+
Tcl_WrongNumArgs(interp,2,objv,"style ?-option ?value...??");
|
|
1261
|
+
return TCL_ERROR;
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
styleName = Tcl_GetString(objv[2]);
|
|
1265
|
+
stylePtr = Ttk_GetStyle(theme, styleName);
|
|
1266
|
+
|
|
1267
|
+
if (objc == 3) { /* style default $styleName */
|
|
1268
|
+
Tcl_SetObjResult(interp, HashTableToDict(&stylePtr->defaultsTable));
|
|
1269
|
+
return TCL_OK;
|
|
1270
|
+
} else if (objc == 4) { /* style default $styleName -option */
|
|
1271
|
+
const char *optionName = Tcl_GetString(objv[3]);
|
|
1272
|
+
Tcl_HashEntry *entryPtr =
|
|
1273
|
+
Tcl_FindHashEntry(&stylePtr->defaultsTable, optionName);
|
|
1274
|
+
if (entryPtr) {
|
|
1275
|
+
Tcl_SetObjResult(interp, (Tcl_Obj*)Tcl_GetHashValue(entryPtr));
|
|
1276
|
+
}
|
|
1277
|
+
return TCL_OK;
|
|
1278
|
+
} else if (objc % 2 != 1) {
|
|
1279
|
+
goto usage;
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
for (i = 3; i < objc; i += 2) {
|
|
1283
|
+
const char *optionName = Tcl_GetString(objv[i]);
|
|
1284
|
+
Tcl_Obj *value = objv[i+1];
|
|
1285
|
+
Tcl_HashEntry *entryPtr;
|
|
1286
|
+
int newEntry;
|
|
1287
|
+
|
|
1288
|
+
entryPtr = Tcl_CreateHashEntry(
|
|
1289
|
+
&stylePtr->defaultsTable,optionName,&newEntry);
|
|
1290
|
+
|
|
1291
|
+
Tcl_IncrRefCount(value);
|
|
1292
|
+
if (!newEntry) {
|
|
1293
|
+
Tcl_DecrRefCount((Tcl_Obj*)Tcl_GetHashValue(entryPtr));
|
|
1294
|
+
}
|
|
1295
|
+
Tcl_SetHashValue(entryPtr, value);
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
ThemeChanged(pkgPtr);
|
|
1299
|
+
return TCL_OK;
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
/* + style lookup $style -option ?statespec? ?defaultValue?
|
|
1303
|
+
*/
|
|
1304
|
+
static int StyleLookupCmd(
|
|
1305
|
+
ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[])
|
|
1306
|
+
{
|
|
1307
|
+
StylePackageData *pkgPtr = clientData;
|
|
1308
|
+
Ttk_Theme theme = pkgPtr->currentTheme;
|
|
1309
|
+
Ttk_Style style = NULL;
|
|
1310
|
+
const char *optionName;
|
|
1311
|
+
Ttk_State state = 0ul;
|
|
1312
|
+
Tcl_Obj *result;
|
|
1313
|
+
|
|
1314
|
+
if (objc < 4 || objc > 6) {
|
|
1315
|
+
Tcl_WrongNumArgs(interp, 2, objv, "style -option ?state? ?default?");
|
|
1316
|
+
return TCL_ERROR;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
style = Ttk_GetStyle(theme, Tcl_GetString(objv[2]));
|
|
1320
|
+
if (!style) {
|
|
1321
|
+
return TCL_ERROR;
|
|
1322
|
+
}
|
|
1323
|
+
optionName = Tcl_GetString(objv[3]);
|
|
1324
|
+
|
|
1325
|
+
if (objc >= 5) {
|
|
1326
|
+
Ttk_StateSpec stateSpec;
|
|
1327
|
+
/* @@@ SB: Ttk_GetStateFromObj(); 'offbits' spec is ignored */
|
|
1328
|
+
if (Ttk_GetStateSpecFromObj(interp, objv[4], &stateSpec) != TCL_OK) {
|
|
1329
|
+
return TCL_ERROR;
|
|
1330
|
+
}
|
|
1331
|
+
state = stateSpec.onbits;
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
result = Ttk_QueryStyle(style, NULL,NULL, optionName, state);
|
|
1335
|
+
if (result == NULL && objc >= 6) { /* Use caller-supplied fallback */
|
|
1336
|
+
result = objv[5];
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
if (result) {
|
|
1340
|
+
Tcl_SetObjResult(interp, result);
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
return TCL_OK;
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
/* + style theme create name ?-parent $theme? ?-settings { script }?
|
|
1347
|
+
*/
|
|
1348
|
+
static int StyleThemeCreateCmd(
|
|
1349
|
+
ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[])
|
|
1350
|
+
{
|
|
1351
|
+
StylePackageData *pkgPtr = (StylePackageData *)clientData;
|
|
1352
|
+
static const char *optStrings[] =
|
|
1353
|
+
{ "-parent", "-settings", NULL };
|
|
1354
|
+
enum { OP_PARENT, OP_SETTINGS };
|
|
1355
|
+
Ttk_Theme parentTheme = pkgPtr->defaultTheme, newTheme;
|
|
1356
|
+
Tcl_Obj *settingsScript = NULL;
|
|
1357
|
+
const char *themeName;
|
|
1358
|
+
int i;
|
|
1359
|
+
|
|
1360
|
+
if (objc < 4 || objc % 2 != 0) {
|
|
1361
|
+
Tcl_WrongNumArgs(interp, 3, objv, "name ?options?");
|
|
1362
|
+
return TCL_ERROR;
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
themeName = Tcl_GetString(objv[3]);
|
|
1366
|
+
|
|
1367
|
+
for (i=4; i < objc; i +=2) {
|
|
1368
|
+
int option;
|
|
1369
|
+
if (Tcl_GetIndexFromObj(
|
|
1370
|
+
interp, objv[i], optStrings, "option", 0, &option) != TCL_OK)
|
|
1371
|
+
{
|
|
1372
|
+
return TCL_ERROR;
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
switch (option) {
|
|
1376
|
+
case OP_PARENT:
|
|
1377
|
+
parentTheme = LookupTheme(
|
|
1378
|
+
interp, pkgPtr, Tcl_GetString(objv[i+1]));
|
|
1379
|
+
if (!parentTheme)
|
|
1380
|
+
return TCL_ERROR;
|
|
1381
|
+
break;
|
|
1382
|
+
case OP_SETTINGS:
|
|
1383
|
+
settingsScript = objv[i+1];
|
|
1384
|
+
break;
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
newTheme = Ttk_CreateTheme(interp, themeName, parentTheme);
|
|
1389
|
+
if (!newTheme) {
|
|
1390
|
+
return TCL_ERROR;
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
/*
|
|
1394
|
+
* Evaluate the -settings script, if supplied:
|
|
1395
|
+
*/
|
|
1396
|
+
if (settingsScript) {
|
|
1397
|
+
Ttk_Theme oldTheme = pkgPtr->currentTheme;
|
|
1398
|
+
int status;
|
|
1399
|
+
|
|
1400
|
+
pkgPtr->currentTheme = newTheme;
|
|
1401
|
+
status = Tcl_EvalObjEx(interp, settingsScript, 0);
|
|
1402
|
+
pkgPtr->currentTheme = oldTheme;
|
|
1403
|
+
return status;
|
|
1404
|
+
} else {
|
|
1405
|
+
return TCL_OK;
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
/* + style theme names --
|
|
1410
|
+
* Return list of registered themes.
|
|
1411
|
+
*/
|
|
1412
|
+
static int StyleThemeNamesCmd(
|
|
1413
|
+
ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[])
|
|
1414
|
+
{
|
|
1415
|
+
StylePackageData *pkgPtr = clientData;
|
|
1416
|
+
return EnumerateHashTable(interp, &pkgPtr->themeTable);
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
/* + style theme settings $theme $script
|
|
1420
|
+
*
|
|
1421
|
+
* Temporarily sets the current theme to $themeName,
|
|
1422
|
+
* evaluates $script, then restores the old theme.
|
|
1423
|
+
*/
|
|
1424
|
+
static int
|
|
1425
|
+
StyleThemeSettingsCmd(
|
|
1426
|
+
ClientData clientData, /* Master StylePackageData pointer */
|
|
1427
|
+
Tcl_Interp *interp, /* Current interpreter */
|
|
1428
|
+
int objc, /* Number of arguments */
|
|
1429
|
+
Tcl_Obj * CONST objv[]) /* Argument objects */
|
|
1430
|
+
{
|
|
1431
|
+
StylePackageData *pkgPtr = (StylePackageData *)clientData;
|
|
1432
|
+
Ttk_Theme oldTheme = pkgPtr->currentTheme;
|
|
1433
|
+
Ttk_Theme newTheme;
|
|
1434
|
+
int status;
|
|
1435
|
+
|
|
1436
|
+
if (objc != 5) {
|
|
1437
|
+
Tcl_WrongNumArgs(interp, 3, objv, "theme script");
|
|
1438
|
+
return TCL_ERROR;
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
newTheme = LookupTheme(interp, pkgPtr, Tcl_GetString(objv[3]));
|
|
1442
|
+
if (!newTheme)
|
|
1443
|
+
return TCL_ERROR;
|
|
1444
|
+
|
|
1445
|
+
pkgPtr->currentTheme = newTheme;
|
|
1446
|
+
status = Tcl_EvalObjEx(interp, objv[4], 0);
|
|
1447
|
+
pkgPtr->currentTheme = oldTheme;
|
|
1448
|
+
|
|
1449
|
+
return status;
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
/* + style element create name type ? ...args ?
|
|
1453
|
+
*/
|
|
1454
|
+
static int StyleElementCreateCmd(
|
|
1455
|
+
ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[])
|
|
1456
|
+
{
|
|
1457
|
+
StylePackageData *pkgPtr = (StylePackageData *)clientData;
|
|
1458
|
+
Ttk_Theme theme = pkgPtr->currentTheme;
|
|
1459
|
+
const char *elementName, *factoryName;
|
|
1460
|
+
Tcl_HashEntry *entryPtr;
|
|
1461
|
+
FactoryRec *recPtr;
|
|
1462
|
+
|
|
1463
|
+
if (objc < 5) {
|
|
1464
|
+
Tcl_WrongNumArgs(interp, 3, objv, "name type ?options...?");
|
|
1465
|
+
return TCL_ERROR;
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
elementName = Tcl_GetString(objv[3]);
|
|
1469
|
+
factoryName = Tcl_GetString(objv[4]);
|
|
1470
|
+
|
|
1471
|
+
entryPtr = Tcl_FindHashEntry(&pkgPtr->factoryTable, factoryName);
|
|
1472
|
+
if (!entryPtr) {
|
|
1473
|
+
Tcl_AppendResult(interp, "No such element type ", factoryName, NULL);
|
|
1474
|
+
return TCL_ERROR;
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
recPtr = (FactoryRec *)Tcl_GetHashValue(entryPtr);
|
|
1478
|
+
|
|
1479
|
+
return recPtr->factory(interp, recPtr->clientData,
|
|
1480
|
+
theme, elementName, objc - 5, objv + 5);
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
/* + style element names --
|
|
1484
|
+
* Return a list of elements defined in the current theme.
|
|
1485
|
+
*/
|
|
1486
|
+
static int StyleElementNamesCmd(
|
|
1487
|
+
ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[])
|
|
1488
|
+
{
|
|
1489
|
+
StylePackageData *pkgPtr = (StylePackageData *)clientData;
|
|
1490
|
+
Ttk_Theme theme = pkgPtr->currentTheme;
|
|
1491
|
+
|
|
1492
|
+
if (objc != 3) {
|
|
1493
|
+
Tcl_WrongNumArgs(interp, 3, objv, NULL);
|
|
1494
|
+
return TCL_ERROR;
|
|
1495
|
+
}
|
|
1496
|
+
return EnumerateHashTable(interp, &theme->elementTable);
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
/* + style element options $element --
|
|
1500
|
+
* Return list of element options for specified element
|
|
1501
|
+
*/
|
|
1502
|
+
static int StyleElementOptionsCmd(
|
|
1503
|
+
ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[])
|
|
1504
|
+
{
|
|
1505
|
+
StylePackageData *pkgPtr = clientData;
|
|
1506
|
+
Ttk_Theme theme = pkgPtr->currentTheme;
|
|
1507
|
+
const char *elementName;
|
|
1508
|
+
ElementImpl *elementImpl;
|
|
1509
|
+
|
|
1510
|
+
if (objc != 4) {
|
|
1511
|
+
Tcl_WrongNumArgs(interp, 3, objv, "element");
|
|
1512
|
+
return TCL_ERROR;
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
elementName = Tcl_GetString(objv[3]);
|
|
1516
|
+
elementImpl = Ttk_GetElement(theme, elementName);
|
|
1517
|
+
if (elementImpl) {
|
|
1518
|
+
Ttk_ElementSpec *specPtr = elementImpl->specPtr;
|
|
1519
|
+
Ttk_ElementOptionSpec *option = specPtr->options;
|
|
1520
|
+
Tcl_Obj *result = Tcl_NewListObj(0,0);
|
|
1521
|
+
|
|
1522
|
+
while (option->optionName) {
|
|
1523
|
+
Tcl_ListObjAppendElement(
|
|
1524
|
+
interp, result, Tcl_NewStringObj(option->optionName,-1));
|
|
1525
|
+
++option;
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
Tcl_SetObjResult(interp, result);
|
|
1529
|
+
return TCL_OK;
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
Tcl_AppendResult(interp, "element ", elementName, " not found", NULL);
|
|
1533
|
+
return TCL_ERROR;
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
/* + style layout name ?spec?
|
|
1537
|
+
*/
|
|
1538
|
+
static int StyleLayoutCmd(
|
|
1539
|
+
ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[])
|
|
1540
|
+
{
|
|
1541
|
+
StylePackageData *pkgPtr = (StylePackageData *)clientData;
|
|
1542
|
+
Ttk_Theme theme = pkgPtr->currentTheme;
|
|
1543
|
+
const char *layoutName;
|
|
1544
|
+
Ttk_LayoutTemplate layoutTemplate;
|
|
1545
|
+
|
|
1546
|
+
if (objc < 3 || objc > 4) {
|
|
1547
|
+
Tcl_WrongNumArgs(interp, 2, objv, "name ?spec?");
|
|
1548
|
+
return TCL_ERROR;
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
layoutName = Tcl_GetString(objv[2]);
|
|
1552
|
+
|
|
1553
|
+
if (objc == 3) {
|
|
1554
|
+
layoutTemplate = Ttk_FindLayoutTemplate(theme, layoutName);
|
|
1555
|
+
if (!layoutTemplate) {
|
|
1556
|
+
Tcl_AppendResult(interp, "Layout ", layoutName, " not found", NULL);
|
|
1557
|
+
return TCL_ERROR;
|
|
1558
|
+
}
|
|
1559
|
+
Tcl_SetObjResult(interp, Ttk_UnparseLayoutTemplate(layoutTemplate));
|
|
1560
|
+
} else {
|
|
1561
|
+
layoutTemplate = Ttk_ParseLayoutTemplate(interp, objv[3]);
|
|
1562
|
+
if (!layoutTemplate) {
|
|
1563
|
+
return TCL_ERROR;
|
|
1564
|
+
}
|
|
1565
|
+
Ttk_RegisterLayoutTemplate(theme, layoutName, layoutTemplate);
|
|
1566
|
+
ThemeChanged(pkgPtr);
|
|
1567
|
+
}
|
|
1568
|
+
return TCL_OK;
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
/* + style theme use $theme --
|
|
1572
|
+
* Sets the current theme to $theme
|
|
1573
|
+
*/
|
|
1574
|
+
static int
|
|
1575
|
+
StyleThemeUseCmd(
|
|
1576
|
+
ClientData clientData, /* Master StylePackageData pointer */
|
|
1577
|
+
Tcl_Interp *interp, /* Current interpreter */
|
|
1578
|
+
int objc, /* Number of arguments */
|
|
1579
|
+
Tcl_Obj * CONST objv[]) /* Argument objects */
|
|
1580
|
+
{
|
|
1581
|
+
StylePackageData *pkgPtr = clientData;
|
|
1582
|
+
Ttk_Theme theme;
|
|
1583
|
+
|
|
1584
|
+
if (objc != 4) {
|
|
1585
|
+
Tcl_WrongNumArgs(interp, 3, objv, "theme");
|
|
1586
|
+
return TCL_ERROR;
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
theme = LookupTheme(interp, pkgPtr, Tcl_GetString(objv[3]));
|
|
1590
|
+
if (!theme) {
|
|
1591
|
+
return TCL_ERROR;
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
return Ttk_UseTheme(interp, theme);
|
|
1595
|
+
}
|
|
1596
|
+
|
|
1597
|
+
/*
|
|
1598
|
+
* StyleObjCmd --
|
|
1599
|
+
* Implementation of the [style] command.
|
|
1600
|
+
*/
|
|
1601
|
+
|
|
1602
|
+
struct Ensemble {
|
|
1603
|
+
const char *name; /* subcommand name */
|
|
1604
|
+
Tcl_ObjCmdProc *command; /* subcommand implementation, OR: */
|
|
1605
|
+
struct Ensemble *ensemble; /* subcommand ensemble */
|
|
1606
|
+
};
|
|
1607
|
+
|
|
1608
|
+
static struct Ensemble StyleThemeEnsemble[] = {
|
|
1609
|
+
{ "create", StyleThemeCreateCmd, 0 },
|
|
1610
|
+
{ "names", StyleThemeNamesCmd, 0 },
|
|
1611
|
+
{ "settings", StyleThemeSettingsCmd, 0 },
|
|
1612
|
+
{ "use", StyleThemeUseCmd, 0 },
|
|
1613
|
+
{ NULL, 0, 0 }
|
|
1614
|
+
};
|
|
1615
|
+
|
|
1616
|
+
static struct Ensemble StyleElementEnsemble[] = {
|
|
1617
|
+
{ "create", StyleElementCreateCmd, 0 },
|
|
1618
|
+
{ "names", StyleElementNamesCmd, 0 },
|
|
1619
|
+
{ "options", StyleElementOptionsCmd, 0 },
|
|
1620
|
+
{ NULL, 0, 0 }
|
|
1621
|
+
};
|
|
1622
|
+
|
|
1623
|
+
static struct Ensemble StyleEnsemble[] = {
|
|
1624
|
+
{ "configure", StyleConfigureCmd, 0 },
|
|
1625
|
+
{ "map", StyleMapCmd, 0 },
|
|
1626
|
+
{ "lookup", StyleLookupCmd, 0 },
|
|
1627
|
+
{ "layout", StyleLayoutCmd, 0 },
|
|
1628
|
+
{ "theme", 0, StyleThemeEnsemble },
|
|
1629
|
+
{ "element", 0, StyleElementEnsemble },
|
|
1630
|
+
{ NULL, 0, 0 }
|
|
1631
|
+
};
|
|
1632
|
+
|
|
1633
|
+
static int
|
|
1634
|
+
StyleObjCmd(
|
|
1635
|
+
ClientData clientData, /* Master StylePackageData pointer */
|
|
1636
|
+
Tcl_Interp *interp, /* Current interpreter */
|
|
1637
|
+
int objc, /* Number of arguments */
|
|
1638
|
+
Tcl_Obj * CONST objv[]) /* Argument objects */
|
|
1639
|
+
{
|
|
1640
|
+
struct Ensemble *ensemble = StyleEnsemble;
|
|
1641
|
+
int optPtr = 1;
|
|
1642
|
+
int index;
|
|
1643
|
+
|
|
1644
|
+
while (optPtr < objc) {
|
|
1645
|
+
if (Tcl_GetIndexFromObjStruct(interp,
|
|
1646
|
+
objv[optPtr], ensemble, sizeof(ensemble[0]),
|
|
1647
|
+
"command", 0, &index)
|
|
1648
|
+
!= TCL_OK)
|
|
1649
|
+
{
|
|
1650
|
+
return TCL_ERROR;
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
if (ensemble[index].command) {
|
|
1654
|
+
return ensemble[index].command(clientData, interp, objc, objv);
|
|
1655
|
+
}
|
|
1656
|
+
ensemble = ensemble[index].ensemble;
|
|
1657
|
+
++optPtr;
|
|
1658
|
+
}
|
|
1659
|
+
Tcl_WrongNumArgs(interp, optPtr, objv, "option ?arg arg...?");
|
|
1660
|
+
return TCL_ERROR;
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
/*
|
|
1664
|
+
* Ttk_StylePkgInit --
|
|
1665
|
+
* Initializes all the structures that are used by the style
|
|
1666
|
+
* package on a per-interp basis.
|
|
1667
|
+
*/
|
|
1668
|
+
|
|
1669
|
+
void Ttk_StylePkgInit(Tcl_Interp *interp)
|
|
1670
|
+
{
|
|
1671
|
+
StylePackageData *pkgPtr = (StylePackageData *)
|
|
1672
|
+
ckalloc(sizeof(StylePackageData));
|
|
1673
|
+
|
|
1674
|
+
pkgPtr->interp = interp;
|
|
1675
|
+
Tcl_InitHashTable(&pkgPtr->themeTable, TCL_STRING_KEYS);
|
|
1676
|
+
Tcl_InitHashTable(&pkgPtr->factoryTable, TCL_STRING_KEYS);
|
|
1677
|
+
pkgPtr->cleanupList = NULL;
|
|
1678
|
+
pkgPtr->cache = Ttk_CreateResourceCache(interp);
|
|
1679
|
+
pkgPtr->themeChangePending = 0;
|
|
1680
|
+
|
|
1681
|
+
Tcl_SetAssocData(interp, "StylePackage", Ttk_StylePkgFree,
|
|
1682
|
+
(ClientData)pkgPtr);
|
|
1683
|
+
|
|
1684
|
+
/*
|
|
1685
|
+
* Create the default system theme:
|
|
1686
|
+
*
|
|
1687
|
+
* pkgPtr->defaultTheme must be initialized to 0 before
|
|
1688
|
+
* calling Ttk_CreateTheme for the first time, since it's used
|
|
1689
|
+
* as the parent theme.
|
|
1690
|
+
*/
|
|
1691
|
+
pkgPtr->defaultTheme = 0;
|
|
1692
|
+
pkgPtr->defaultTheme = pkgPtr->currentTheme =
|
|
1693
|
+
Ttk_CreateTheme(interp, "default", NULL);
|
|
1694
|
+
|
|
1695
|
+
/*
|
|
1696
|
+
* Register null element, used as a last-resort fallback:
|
|
1697
|
+
*/
|
|
1698
|
+
Ttk_RegisterElement(interp, pkgPtr->defaultTheme, "", &ttkNullElementSpec, 0);
|
|
1699
|
+
|
|
1700
|
+
/*
|
|
1701
|
+
* Register commands:
|
|
1702
|
+
*/
|
|
1703
|
+
Tcl_CreateObjCommand(interp, "::ttk::style", StyleObjCmd,
|
|
1704
|
+
(ClientData)pkgPtr, 0);
|
|
1705
|
+
Ttk_RegisterElementFactory(interp, "from", Ttk_CloneElement, 0);
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
/*EOF*/
|