root/trunk/luigi/theme.d

Revision 52, 7.2 kB (checked in by baxissimo, 2 years ago)

Fixed incorrect logic in handling ev.alive.

Line 
1 //---------------------------------------------------------------------
2 /*
3  Copyright:
4
5   luigi/theme.d -- theme support for 'luigi' user interface library.
6
7   Copyright (C) 2006 William V. Baxter III
8
9   This software is provided 'as-is', without any express or implied
10   warranty.  In no event will the authors be held liable for any
11   damages arising from the use of this software.
12
13   Permission is granted to anyone to use this software for any
14   purpose, including commercial applications, and to alter it and
15   redistribute it freely, subject to the following restrictions:
16
17   1. The origin of this software must not be misrepresented; you must
18      not claim that you wrote the original software. If you use this
19      software in a product, an acknowledgment in the product
20      documentation would be appreciated but is not required.
21
22   2. Altered source versions must be plainly marked as such, and must
23      not be misrepresented as being the original software.
24   3. This notice may not be removed or altered from any source distribution.
25
26   William Baxter wbaxter@gmail.com
27 */
28 module luigi.theme;
29
30
31 import luigi.base;
32 import luigi.opengl;
33 import luigi.gldraw;
34 import luigi.font;
35 import luigi.event;
36
37 import luigi.gui;
38 //import luigi.widgets.widget;
39
40 //--------------------------------------------------------------------------
41 /** An abstract interface for themes used by Luigi */
42 interface Theme
43 {
44     /** Called before and after refreshing the gui by Overlay.
45      *  This is where all common 2D GL state can be set up and restored by
46      *  the theme.
47      */
48     void begin_drawing(Rect r);
49     void end_drawing();
50
51     /** Draws the given item */
52     void draw(Widget item);
53
54     /** Sizes used for layout */
55     Size minimum_size(Widget item, Size bounds);
56     Size preferred_size(Widget item, Size bounds);
57
58     /** Event handling */
59     void on_key(Widget item, KeyEvent ev);
60     void on_mouse_button(Widget item, MouseButtonEvent ev);
61     void on_mouse_move(Widget item, MouseMoveEvent ev);
62     void on_mouse_wheel(Widget item, MouseWheelEvent ev);
63     void on_focus(Widget item, FocusEvent ev);
64
65     // need sizes
66     // need states? naw can get it from control
67 }
68
69 class AbstractTheme : Theme
70 {
71     abstract override void draw(Widget item);
72     abstract override Size minimum_size(Widget item, Size bounds);
73     abstract override Size preferred_size(Widget item, Size bounds);
74
75     void begin_drawing(Rect r) {}
76     void end_drawing() {}
77
78     //============================================================================
79     // Event functions
80     override void on_key(Widget item, KeyEvent ev) {
81         // this really isn't that theme specific...
82         item.on_key(ev);
83     }
84     override void on_mouse_button(Widget item, MouseButtonEvent ev) {
85         item.on_mouse_button(ev);
86     }
87     override void on_mouse_move(Widget item, MouseMoveEvent ev) {
88         item.on_mouse_move(ev);
89     }
90     override void on_mouse_wheel(Widget item, MouseWheelEvent ev) {
91         item.on_mouse_wheel(ev);
92     }
93     override void on_focus(Widget item, FocusEvent ev) {
94         item.on_focus(ev);
95     }
96 }
97
98 /** This template/mixin provides helper functions used by themes to
99  *  manage per-class instance information.
100  */
101 template WidgetClassInfoDict(FuncT)
102 {
103     /** Lookup Widget class-specific data in a table.
104      * 
105      * This is like an ordinary AA lookup keyed on ClassInfo,
106      * but if a key is missing it recursively tries all the ClassInfo
107      * objects for the base classes as well. 
108      * If it finds a match, that match is copied to
109      * table[item.classinfo] for faster future lookups.
110      */
111     FuncT lookup(inout FuncT[ClassInfo] table, Widget item) {
112         // Search for func in the table, going up class hierarchy
113         ClassInfo start = item.classinfo;
114         if (start in table) return table[start];
115         ClassInfo stop = Widget.classinfo;
116         for(auto cinfo=start; cinfo!=stop; cinfo=cinfo.base)
117         {
118             if (cinfo in table) {
119                 FuncT f = table[cinfo];
120                 table[start] = f; // cache result for later
121                 return f;
122             }
123         }
124         return null;
125     }   
126     /** Same as lookup(table,item) but use the mixin's builtin m_table */
127     FuncT lookup(Widget item) {
128         return lookup(m_table,item);
129     }
130
131     /** Add an element to the ClassInfo-keyed table */
132     void add(inout FuncT[ClassInfo] table, ClassInfo c, FuncT f) {
133         table[c] = f;
134     }
135     /** Same as add(table,c,f) but use the mixin's builtin m_table */
136     void add(ClassInfo c, FuncT f) {
137         add(m_table, c, f);
138     }
139     FuncT[ClassInfo] m_table;
140 }
141
142
143 class ThemeBase : AbstractTheme
144 {
145     alias Size delegate(Widget item, Size bounds) SizeFunc;
146     alias void delegate(Widget item) DrawFunc;
147
148     alias void delegate(Widget item, MouseButtonEvent ev) ButtonFunc;
149     alias void delegate(Widget item, MouseMoveEvent ev) MoveFunc;
150     alias void delegate(Widget item, KeyEvent ev) KeyFunc;
151
152     void addHandlers(alias Class)(DrawFunc draw, SizeFunc best_sz, SizeFunc min_sz=null )
153     {
154         m_drawFuncs.add(Class.classinfo, draw);
155         m_bestsizeFuncs.add(Class.classinfo, best_sz);
156         m_minsizeFuncs.add(Class.classinfo, (min_sz is null)?best_sz : min_sz);
157     }
158     void addEventHandlers(alias Class)(ButtonFunc btn, MoveFunc move=null, KeyFunc key=null )
159     {
160         m_btnFuncs.add(Class.classinfo, btn);
161         if (move !is null)
162             m_moveFuncs.add(Class.classinfo, move);
163         if (key !is null)
164             m_moveFuncs.add(Class.classinfo, move);
165     }
166
167     protected:
168     mixin WidgetClassInfoDict!(DrawFunc)   m_drawFuncs;
169     mixin WidgetClassInfoDict!(SizeFunc)   m_minsizeFuncs;
170     mixin WidgetClassInfoDict!(SizeFunc)   m_bestsizeFuncs;
171     mixin WidgetClassInfoDict!(ButtonFunc) m_btnFuncs;
172     mixin WidgetClassInfoDict!(MoveFunc)   m_moveFuncs;
173     mixin WidgetClassInfoDict!(KeyFunc)    m_keyFuncs;
174
175     public:
176
177     override void draw(Widget item) {
178         DrawFunc f = m_drawFuncs.lookup(item);
179         if (f) f(item);
180     }
181
182     override Size minimum_size(Widget item, Size bounds) {
183         SizeFunc f = m_minsizeFuncs.lookup(item);
184         if (f) return f(item,bounds);
185         return Size(0,0);
186     }
187
188     override Size preferred_size(Widget item, Size bounds) {
189         SizeFunc f = m_bestsizeFuncs.lookup(item);
190         if (f) {
191             return f(item,bounds);
192         }
193         return Size(50,22);
194     }
195
196     //============================================================================
197     // Event functions
198     override void on_key(Widget item, KeyEvent ev)
199     {
200         KeyFunc f = m_keyFuncs.lookup(item);
201         if (f) f(item, ev);
202         if (!f || ev.alive) { item.on_key(ev); }
203     }
204     override void on_mouse_button(Widget item, MouseButtonEvent ev)
205     {
206         ButtonFunc f = m_btnFuncs.lookup(item);
207         if (f) f(item, ev);
208         if (!f || ev.alive) { item.on_mouse_button(ev); }
209     }
210     override void on_mouse_move(Widget item, MouseMoveEvent ev)
211     {
212         MoveFunc f = m_moveFuncs.lookup(item);
213         if (f)
214             f(item, ev);
215         if (!f || ev.alive) { item.on_mouse_move(ev); }
216     }
217 }
Note: See TracBrowser for help on using the browser.