00001 #ifndef H_SDLPP_GUI
00002 #define H_SDLPP_GUI
00003
00004 #include "callback.h"
00005
00006 namespace SDLPP
00007 {
00008
00009 void PopupMessage(const xstring& msg);
00010 void gui_stub();
00011
00012 class GUITheme
00013 {
00014 public:
00015 static GUITheme* instance()
00016 {
00017 static std::auto_ptr<GUITheme> ptr(new GUITheme);
00018 return ptr.get();
00019 }
00020
00021 void load_theme(const xstring& filename, ResourceFile* rf)
00022 {
00023 xml_element* root=load_xml(filename,rf);
00024 load_theme(root,rf);
00025 }
00026
00027 void load_theme(xml_element* root, ResourceFile* rf)
00028 {
00029 if (root->has_attribute("Font"))
00030 {
00031 if (rf) m_Font=&SDLPP::get_font(*rf,root->get_attribute("Font"),atoi(root->get_attribute("Size").c_str()));
00032 else m_Font=&SDLPP::get_font(root->get_attribute("Font"),atoi(root->get_attribute("Size").c_str()));
00033 }
00034 if (root->has_attribute("TextColor"))
00035 m_TextColor=atoi(root->get_attribute("TextColor").c_str());
00036 xml_element::iterator b=root->begin(),e=root->end();
00037 for(;b!=e;++b)
00038 {
00039 xml_element* el=*b;
00040 xstring name=el->get_attribute("Name");
00041 xstring image_name=el->get_attribute("Image");
00042 if (!name.empty() && !image_name.empty())
00043 {
00044 if (rf) m_Bitmaps[name]=Bitmap(*rf,image_name);
00045 else m_Bitmaps[name]=Bitmap(image_name);
00046 }
00047 }
00048 }
00049
00050 Bitmap& get(const xstring& name)
00051 {
00052 static Bitmap Null(32,32,false);
00053 bmp_map::iterator it=m_Bitmaps.find(name);
00054 if (it==m_Bitmaps.end()) return Null;
00055 return it->second;
00056 }
00057
00058 Font& get_font()
00059 {
00060 if (!m_Font) throw xstring("GUITheme: No font loaded.");
00061 return *m_Font;
00062 }
00063
00064 Uint32 get_text_color()
00065 {
00066 return m_TextColor;
00067 }
00068
00069 private:
00070 friend class std::auto_ptr<GUITheme>;
00071 GUITheme() : m_Font(0), m_TextColor(0x808080) {}
00072 ~GUITheme() {}
00073 GUITheme(const GUITheme&) {}
00074 GUITheme& operator= (const GUITheme&) {}
00075
00076 typedef std::map<xstring,Bitmap> bmp_map;
00077 bmp_map m_Bitmaps;
00078 Font* m_Font;
00079 Uint32 m_TextColor;
00080 };
00081
00082
00083
00084 class Control
00085 {
00086 protected:
00087 Control() : m_Parent(0), m_Enabled(true), m_Valid(false) {}
00088 virtual ~Control() {}
00089 Control(const Control&) {}
00090 Control& operator= (const Control&) { return *this; }
00091
00092 xstring m_Name;
00093 iRect2 m_Rect;
00094 Control* m_Parent;
00095 bool m_Enabled;
00096 bool m_Valid;
00097 public:
00098 friend class Container;
00099
00100 virtual void set_details(xml_element* details) {}
00101 virtual xml_element* get_details() { return new xml_element; }
00102
00103 virtual void enable(bool state=true) { m_Enabled=state; }
00104 virtual void disable() { enable(false); }
00105 virtual bool enabled() { return m_Enabled; }
00106
00107 virtual void invalidate() { m_Valid=false; }
00108 virtual void validate() { m_Valid=true; }
00109 virtual bool valid() const { return m_Valid; }
00110
00111 virtual void set_name(const xstring& name) { m_Name=name; }
00112 virtual const xstring& get_name() const { return m_Name; }
00113 virtual void set_rect(const iRect2& r) { m_Rect=r; }
00114 virtual const iRect2& get_rect() const { return m_Rect; }
00115 virtual Control* get_parent() { return m_Parent; }
00116 virtual const Control* get_parent() const { return m_Parent; }
00117 virtual void draw(Bitmap& target=GraphicsManager::instance()->get_screen(),
00118 const iVec2& offset=iVec2(0,0)) {}
00119 virtual void on_mouse_down(int button, const iVec2& pos) {}
00120 virtual void on_mouse_up (int button, const iVec2& pos) {}
00121 virtual void on_mouse_move(const iVec2& pos) {}
00122 virtual void on_mouse_enter(const iVec2& pos) {}
00123 virtual void on_mouse_leave(const iVec2& pos) {}
00124 virtual void on_char(Uint16 ch) {}
00125 virtual void notify(Control* source, const xstring& message) {}
00126
00127 virtual Control* find_leaf(const iVec2& pos);
00128 virtual Control* find(const xstring& name);
00129 };
00130
00131 class Container : public Control
00132 {
00133 typedef std::list<Control*> ctrlp_list;
00134 ctrlp_list m_Children;
00135 public:
00136 ~Container()
00137 {
00138 clear();
00139 }
00140
00141 void swap(Container& rhs)
00142 {
00143 m_Children.swap(rhs.m_Children);
00144 }
00145
00146 virtual void draw(Bitmap& target, const iVec2& offset)
00147 {
00148 iterator b=begin(),e=end();
00149 for(;b!=e;++b)
00150 {
00151 Control* ctrl=*b;
00152 if (ctrl)
00153 ctrl->draw(target,offset+get_rect().tl);
00154 }
00155 }
00156
00157 void clear()
00158 {
00159 for(iterator it=begin();it!=end();++it) delete (*it);
00160 m_Children.clear();
00161 }
00162
00163 unsigned size() const
00164 {
00165 return m_Children.size();
00166 }
00167
00168 void add_child(Control* ctrl)
00169 {
00170 m_Children.push_back(ctrl);
00171 }
00172
00173 void remove(Control* ctrl)
00174 {
00175 for(iterator b=begin(),e=end();b!=e;++b)
00176 {
00177 Control* c=*b;
00178 if (c==ctrl)
00179 {
00180 m_Children.erase(b);
00181 delete ctrl;
00182 break;
00183 }
00184 }
00185 }
00186
00187 virtual Control* find_leaf(const iVec2& pos);
00188 virtual Control* find(const xstring& name);
00189
00190 typedef ctrlp_list::iterator iterator;
00191 iterator begin() { return m_Children.begin(); }
00192 iterator end() { return m_Children.end(); }
00193 };
00194
00195 class ControlCreator
00196 {
00197 public:
00198 virtual ~ControlCreator() {}
00199 virtual Control* create(xml_element* details) = 0;
00200 };
00201
00202 #define REGISTER_CONTROL(x) \
00203 Control* stub_##x() { return reinterpret_cast<x*>(__LINE__); }\
00204 class x##_Creator : public ControlCreator { public:\
00205 x##_Creator() { ControlFactory::instance()->register_control(#x,this); }\
00206 Control* create(xml_element* details) { return new x(details); }\
00207 } g_##x##_Creator
00208
00209 class ContainerCreator : public ControlCreator
00210 {
00211 public:
00212 virtual Control* create(xml_element* details)
00213 {
00214 return new Container;
00215 }
00216 };
00217
00218 class ControlFactory
00219 {
00220 public:
00221 static ControlFactory* instance()
00222 {
00223 static std::auto_ptr<ControlFactory> ptr(new ControlFactory);
00224 return ptr.get();
00225 }
00226
00227 void register_control(const xstring& type, ControlCreator* cc)
00228 {
00229 m_Creators[type]=cc;
00230 }
00231
00232 Control* create(const xstring& xml)
00233 {
00234 xml_element* root=load_xml_from_text(xml);
00235 return create(root);
00236 }
00237
00238 Control* create(xml_element* root)
00239 {
00240 xstring type=root->get_type();
00241 crt_map::iterator it=m_Creators.find(type);
00242 if (it==m_Creators.end()) return 0;
00243 Control* ctrl=it->second->create(root);
00244 ctrl->set_rect(parse_rect(root->get_attribute("Rect")));
00245 if (root->has_attribute("Name"))
00246 ctrl->set_name(root->get_attribute("Name"));
00247 return ctrl;
00248 }
00249
00250 private:
00251 friend class std::auto_ptr<ControlFactory>;
00252 ControlFactory()
00253 {
00254 register_control("Container",&m_ContainerCreator);
00255 }
00256 ~ControlFactory() {}
00257 ControlFactory(const ControlFactory&) {}
00258 ControlFactory& operator= (const ControlFactory&) {}
00259
00260 typedef std::map<xstring,ControlCreator*> crt_map;
00261 crt_map m_Creators;
00262 ContainerCreator m_ContainerCreator;
00263 };
00264
00265 class GUI : public EventListener
00266 {
00267 public:
00268 static GUI* instance()
00269 {
00270 static std::auto_ptr<GUI> ptr(new GUI);
00271 return ptr.get();
00272 }
00273
00274 virtual bool handle_event(const SDL_Event& event)
00275 {
00276 Uint8 button=event.button.which;
00277 switch (event.type)
00278 {
00279 case SDL_MOUSEBUTTONDOWN: on_mouse_down(button,event.button.x,event.button.y); return true;
00280 case SDL_MOUSEBUTTONUP: on_mouse_up (button,event.button.x,event.button.y); return true;
00281 case SDL_MOUSEMOTION: on_mouse_move(event.motion.x,event.motion.y); return true;
00282 }
00283 return false;
00284 }
00285
00286 template<class T>
00287 void register_listener(const xstring& name, const xstring& event, T* obj, void (T::*m)(const xstring&))
00288 {
00289 register_listener(name,event,new MethodCaller<T>(*obj,m));
00290 }
00291
00292 void register_listener(const xstring& name, const xstring& event, GenericCaller* caller)
00293 {
00294 m_Listeners[name+"/"+event]=caller;
00295 }
00296
00297 void raise_event(const xstring& name, const xstring& event_type, const xstring& details="")
00298 {
00299 log("Event from '"+name+"' type='"+event_type+"' details='"+details+"'");
00300 xstring ev=name+"/"+event_type;
00301 m_EventQueue.push_back(std::make_pair(ev,details));
00302 }
00303
00304 void dispatch_events()
00305 {
00306 while (!m_EventQueue.empty())
00307 {
00308 const xstring& ev=m_EventQueue.front().first;
00309 const xstring& details=m_EventQueue.front().second;
00310 listener_map::iterator it=m_Listeners.find(ev);
00311 if (it!=m_Listeners.end())
00312 {
00313 GenericCaller* cb=it->second;
00314 cb->call(details);
00315 }
00316 if (!m_EventQueue.empty())
00317 m_EventQueue.pop_front();
00318 }
00319 }
00320
00321 Control* find(const xstring& name);
00322
00323 Control* get_focus()
00324 {
00325 return m_Focus;
00326 }
00327
00328 Container* get_screen_container()
00329 {
00330 return &m_ScreenContainer;
00331 }
00332
00333 void log(const xstring& line)
00334 {
00335
00336 }
00337
00338 void load(const xstring& xml, ResourceFile* rf=0)
00339 {
00340 load(load_xml(xml,rf));
00341 }
00342
00343 void load(xml_element* root);
00344
00345 void draw()
00346 {
00347 get_screen_container()->draw(get_screen(),iVec2(0,0));
00348 }
00349
00350 void push();
00351 void pop();
00352
00353 private:
00354 void on_mouse_down(int button, int x, int y);
00355 void on_mouse_up (int button, int x, int y);
00356 void on_mouse_move(int x, int y);
00357 void on_key(const xstring& s);
00358
00359
00360 friend class std::auto_ptr<GUI>;
00361 GUI()
00362 :
00363 m_Focus(0),
00364 m_MouseIn(0)
00365 {
00366 gui_stub();
00367 iVec2 size=GraphicsManager::instance()->get_screen().get_size();
00368 m_ScreenContainer.set_rect(iRect2(0,0,size.x,size.y));
00369 LISTEN_FOR_EVENT(SDL_MOUSEMOTION);
00370 LISTEN_FOR_EVENT(SDL_MOUSEBUTTONDOWN);
00371 LISTEN_FOR_EVENT(SDL_MOUSEBUTTONUP);
00372 register_listener("Keyboard","Key",this,&GUI::on_key);
00373 }
00374 ~GUI() {}
00375 GUI(const GUI&) {}
00376 GUI& operator= (const GUI&) {}
00377
00378 typedef std::pair<xstring,xstring> str_pair;
00379 typedef std::list<str_pair> event_queue;
00380 typedef std::map<xstring,GenericCaller*> listener_map;
00381
00382 struct StackFrame
00383 {
00384 Container screen;
00385 listener_map listeners;
00386 };
00387
00388 typedef std::list<StackFrame> gui_stack;
00389
00390 gui_stack m_GUIStack;
00391
00392 Container m_ScreenContainer;
00393 listener_map m_Listeners;
00394 event_queue m_EventQueue;
00395
00396 Control* m_Focus;
00397 Control* m_MouseIn;
00398 };
00399
00400 #define LOAD_GUI(x,rf) GUI::instance()->load(x,rf)
00401 #define DRAW_GUI SDLPP::GUI::instance()->draw()
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411 #define RAISE_EVENT(event) GUI::instance()->raise_event(get_name(),event,"")
00412 #define RAISE_DETAILED_EVENT(event,details) GUI::instance()->raise_event(get_name(),event,details)
00413 #define ON_GUI_EVENT(name,event,Class,method) GUI::instance()->register_listener(name,event,this,&Class::method)
00414
00415
00416
00417 }
00418
00419 #endif // H_SDLPP_GUI
00420