1 /*--License: 2 Kyra Sprite Engine 3 Copyright Lee Thomason (Grinning Lizard Software) 2001-2005 4 www.grinninglizard.com/kyra 5 www.sourceforge.net/projects/kyra 6 7 Kyra is provided under the LGPL. 8 9 I kindly request you display a splash screen (provided in the HTML documentation) 10 to promote Kyra and acknowledge the software and everyone who has contributed to it, 11 but it is not required by the license. 12 13 --- LGPL License -- 14 15 This library is free software; you can redistribute it and/or 16 modify it under the terms of the GNU Lesser General Public 17 License as published by the Free Software Foundation; either 18 version 2.1 of the License, or (at your option) any later version. 19 20 This library is distributed in the hope that it will be useful, 21 but WITHOUT ANY WARRANTY; without even the implied warranty of 22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23 Lesser General Public License for more details. 24 25 You should have received a copy of the GNU Lesser General Public 26 License along with this library; if not, write to the Free Software 27 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 29 The full text of the license can be found in lgpl.txt 30 */ 31 32 33 #ifndef KYRA_WIDGET_INCLUDED 34 #define KYRA_WIDGET_INCLUDED 35 36 #ifdef _MSC_VER 37 #pragma warning( disable : 4530 ) 38 #pragma warning( disable : 4786 ) 39 #endif 40 41 #include <string> 42 #include "SDL.h" 43 #include "../util/gllist.h" 44 #include "../../grinliz/glpublisher.h" 45 #include "../engine/engine.h" 46 #include "../engine/color.h" 47 48 49 /** An "activated" event means a switch has turned on, a button has been depressed, etc. 50 */ 51 struct KrWidgetEventActivated 52 { 53 int type; 54 }; 55 56 /** A "Deactivated" event occurs when something that was activated is no longer. 57 */ 58 struct KrWidgetEventDeactivated 59 { 60 int type; 61 }; 62 63 /** A "Command" event has a 'command' and 'argument' string. Usually generated 64 by the console or a similar text based widget that recognizes a set of commands. 65 When a string is split, the first word is the "command" and all that follows is 66 the "arg". If the widget recognized the command - it is in the "command list" - 67 recognized will be set to "true". 68 */ 69 struct KrWidgetEventCommand 70 { 71 int type; 72 bool recognized; 73 const char* command; 74 const char* arg; 75 }; 76 77 /** A "Selection" event is a choice from a set of items. A list box selection for 78 example. It has an 'index' which is a numerical id of the selection, and a 'text' 79 which is the string value. Some widgets don't have text selection, in which case 80 'text' will be null. An ImageListBox will have text==0 for its SELECTION events. 81 */ 82 struct KrWidgetEventSelection 83 { 84 int type; 85 int index; 86 const char* text; 87 }; 88 89 union KrWidgetEvent 90 { 91 enum 92 { 93 NO_EVENT, 94 ACTIVATED, 95 DEACTIVATED, 96 COMMAND, 97 SELECTION, 98 }; 99 100 int type; 101 KrWidgetEventActivated activated; // ACTIVATED 102 KrWidgetEventDeactivated deactivated; // DEACTIVATED 103 KrWidgetEventCommand command; // COMMAND 104 KrWidgetEventSelection selection; // SELECTION 105 }; 106 107 108 /** An abstract class, the HandleWidgetEvent when a widget 109 listener receives an event. The events widgets publish 110 are documented on a per-widget basis. 111 112 The class is abstract, so it can be used as a mix in and 113 there are no multiple inheritance issues. 114 115 The HandleWidgetEvent is a strange method with a lot of 116 paremeters. An obvious solution would be to send a WidgetEvent 117 class that is abstract and polymorphic...but Kyra doesn't use/require 118 dynamic cast, so implementing that is less useful than it 119 seems. 120 */ 121 122 class IKrWidgetListener : public grinliz::Listener< IKrWidgetListener > 123 { 124 public: 125 126 127 virtual bool HandleWidgetEvent( KrWidget* source, const KrWidgetEvent& event ) = 0; 128 }; 129 130 131 /** A scheme defines a color system for widgets. Each widget 132 can have it's own scheme, or an entire widget set can 133 share the same one. (Or at least a copy of the same one.) 134 135 A scheme consists of a font (some widgets allow this to 136 be null), a primary color, and a secondary color that 137 should visually match the primary color, and a cursor 138 color. All other colors used are calculated from the 139 primary and secondary. 140 */ 141 struct KrScheme 142 { 143 KrScheme( KrFontResource* font ); 144 145 KrRGBA CalcBrightLine() const; 146 KrRGBA CalcShadowLine() const; 147 148 KrColorTransform CalcHiPrimary() const; 149 KrColorTransform CalcHiSec() const; 150 KrColorTransform CalcDark() const; 151 KrColorTransform CalcDarkSec() const; 152 153 KrRGBA primary; 154 KrRGBA cursor; 155 KrColorTransform secondary; 156 KrFontResource* font; 157 158 enum 159 { 160 BRIGHT = 60, 161 DARK = 60 162 }; 163 }; 164 165 166 struct KrBevelElement 167 { 168 public: 169 KrBevelElement( int w, int h, const KrScheme& ); 170 ~KrBevelElement(); 171 172 void AddToTree( KrEngine*, KrImNode* parent ); 173 void DrawIn(); 174 void DrawOut(); 175 176 int width; 177 int height; 178 KrBoxResource *vertDR, *vertLR, *horDR, *horLR; 179 KrBox *vertD, *vertL, *horD, *horL; 180 }; 181 182 183 /** This is the base of any Kyra widget. A widget is much like any 184 other Kyra image object. You new it, add it to the KrImageTree, 185 and it is drawn as part of the Draw() pass. 186 187 Widgets don't have resources, but do use schemes which are similar. 188 189 Widgets get their events from an event manager. If you use widgets, 190 you must therefore send events to the KrEventManager class. Widgets 191 generally need SDL_EnableUNICODE( true ) to function correctly. 192 193 Widgets broadcast their events to "listeners." To register a class 194 as a listener, call AddListener(). The class will then receive 195 notification of events. The event each widget broadcast is documented 196 on a per-widget basis. 197 198 A widget subclass can implement any of the following properties: 199 200 - MouseListeners receieve and can respond to mouse events. 201 - KeyListeners get keyboard focus and key messages. They grab 202 key focus with the "tab" key or if clicked on. 203 - Selectable widgets have state. They can be on/off, up/down, or whatever. 204 A KrToggleButton is a selectable widget. 205 - Groupable widgets are in a group, and are aware of other widgets 206 in that group. Radio Buttons are groupable. 207 - Some widgets can respond to accelerator keys. Use SetAccelerator 208 to specify a hotkey to pass to the widget. 209 210 Widgets can be nested and you can query for parents. However, Kyra regards 211 the widget model as flat and doesn't pay attention to the nesting, with 212 one important exception: a key event that isn't handled by a widget 213 will be passed through its parent chain. For example, a KrConsole 214 uses a KrTextWidget. If the KrTextWidget doesn't handle a 215 particular key, it will get passed up to the KrConsole. 216 217 WARNING: You may want to use Widgets in window 0, if you are using multiple Kyra 218 windows. They are not fully tested in higher window numbers. You may see placement 219 or bounding errors in higher window numbers. 220 221 Notes for implementing your own widgets: 222 223 - All Widgets are of the type ToWidget(). To get a particular flavor, 224 the ToExtended() method can be used. 225 - Widgets should initialize themselves in the AddedtoTree() method. When 226 the engine calls your AddedtoTree() method, you can add children because 227 you are already in the Tree(). Be sure to call the parent 228 KrWidget::AddedtoTree() as well! 229 - If you have been added to the Tree(), your Engine() pointer will be non-null. 230 */ 231 class KrWidget : public KrImNode, public IKrWidgetListener 232 { 233 public: 234 virtual ~KrWidget(); ToWidget()235 virtual KrWidget* ToWidget() { return this; } 236 237 /** All widgets publish events through this member. 238 */ 239 grinliz::Publisher< IKrWidgetListener > widgetPublish; 240 241 enum { 242 LEFT_MOUSE = 1, 243 RIGHT_MOUSE = 2, // not currently supported 244 MIDDLE_MOUSE = 4, // not currently supported 245 246 LEFT_UP = 0, 247 LEFT_DOWN = 1, 248 RIGHT_UP = 2, // not currently supported 249 RIGHT_DOWN = 3, // not currently supported 250 MIDDLE_UP = 4, // not currently supported 251 MIDDLE_DOWN = 5 // not currently supported 252 }; 253 WidgetType()254 virtual const char* WidgetType() { return "Widget"; } 255 256 /** IsMouseListener returns whether this is a mouse listener or not, and which buttons 257 are listened to. A return value of 0 is no listening. Else 258 it can return an OR mask of the buttons ( LEFT_MOUSE, RIGHT_MOUSE, 259 MIDDLE_MOUSE ) it wants to listen for mouse clicks. 260 261 The simple case is to only listen to the left mouse, in which case 262 return LEFT_MOUSE (1). The click messages can then be treated like 263 a boolean for the left mouse (1 is down, 0 is up.) 264 265 Currently, with version 2.0, only the LEFT_MOUSE is supported. 266 267 268 MouseIn is called when a mouse moves in to the widget. The 'down' parameter 269 reflects the state of the left mouse button. The 'in' reflects whether 270 it is moving to the widget (true) or away from the widget (false). 271 272 273 MouseMove reports when the mouse moves over this widget. 274 275 276 MouseClick is called when the mouse is clicked on this widget. 277 The 'click' param will have a single value (not OR mask) of 278 LEFT_UP, LEFT_DOWN, RIGHT_UP, etc. with x and y coordinates 279 of the action. 280 281 In the simple case that you are only listening to the left mouse, 282 the parameter will be essentially a boolean: 1 for the left mouse 283 down, 0 for the left mouse up. 284 */ IsMouseListener()285 virtual int IsMouseListener() { return 0; } MouseIn(bool down,bool in)286 virtual void MouseIn( bool down, bool in ) {} ///< @sa IsMouseListener MouseMove(bool down,int x,int y)287 virtual void MouseMove( bool down, int x, int y ) {} ///< @sa IsMouseListener MouseClick(int click,int x,int y)288 virtual bool MouseClick( int click, int x, int y ) { return false; } ///< @sa IsMouseListener 289 IsKeyListener()290 virtual bool IsKeyListener() { return false; } KeyFocus(bool focus)291 virtual void KeyFocus( bool focus ) {} KeyEvent(const SDL_Event & key)292 virtual bool KeyEvent( const SDL_Event& key ) { return false; } 293 IsSelectable()294 virtual bool IsSelectable() { return false; } Selected(bool selected)295 virtual void Selected( bool selected ) {} 296 297 // virtual bool IsGroup() { return false; } 298 Accelerate(bool down)299 virtual void Accelerate( bool down ) {} 300 void SetAccelerator( int keymod, int keysym ); 301 302 /// Handle widget events, return true if handled, false if not ours HandleWidgetEvent(KrWidget * source,const KrWidgetEvent & event)303 virtual bool HandleWidgetEvent( KrWidget* source, const KrWidgetEvent& event ) { return false; } 304 305 /// Find the parent of the widget that is also a widget. 306 KrWidget* ParentWidget(); 307 308 protected: 309 KrWidget( const KrScheme& scheme ); 310 311 int groupId; 312 KrScheme scheme; 313 }; 314 315 #endif 316