DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/libs/gui_tk/gui_tk.h
Go to the documentation of this file.
00001 
00106 #ifndef GUI__TOOLKIT_H
00107 #define GUI__TOOLKIT_H
00108 
00109 #define imin(x,y) ((x)<(y)?(x):(y))
00110 #define imax(x,y) ((x)>(y)?(x):(y))
00111 #define isign(x) (((x)<0?-1:1))
00112 
00119 #ifdef _MSC_VER
00120 typedef signed __int8   int8_t;
00121 typedef signed __int16  int16_t;
00122 typedef signed __int32  int32_t;
00123 typedef unsigned __int8  uint8_t;
00124 typedef unsigned __int16 uint16_t;
00125 typedef unsigned __int32 uint32_t;
00126 #else
00127 #include <stdint.h>
00128 #endif
00129 
00130 #include <list>
00131 #include <map>
00132 #include <vector>
00133 #include <typeinfo>
00134 #include <string>
00135 #include <iostream>
00136 
00138 namespace GUI {
00139 
00141 typedef uint32_t RGB;
00142 
00144 namespace Color {
00146 const RGB Transparent = 0x00ffffff;
00147 
00149 const RGB Black = 0xff000000;
00150 
00152 const RGB White = 0xffffffff;
00153 
00155 const RGB AlphaMask = 0xff000000;
00156 
00158 const int AlphaShift = 24;
00159 
00161 const RGB RedMask = 0x00ff0000;
00162 
00164 const RGB Red = Black|RedMask;
00165 
00167 const int RedShift = 16;
00168 
00170 const RGB GreenMask = 0x0000ff00;
00171 
00173 const RGB Green = Black|GreenMask;
00174 
00176 const int GreenShift = 8;
00177 
00179 const RGB BlueMask = 0x000000ff;
00180 
00182 const RGB Blue = Black|BlueMask;
00183 
00185 const int BlueShift = 0;
00186 
00188 const RGB Magenta = Red|Blue;
00189 
00191 const RGB MagentaMask = RedMask|BlueMask;
00192 
00194 const RGB Cyan = Green|Blue;
00195 
00197 const RGB CyanMask = GreenMask|BlueMask;
00198 
00200 const RGB Yellow = Red|Green;
00201 
00203 const RGB YellowMask = RedMask|GreenMask;
00204 
00206 const RGB Grey50 = 0xff808080;
00207 
00209 extern RGB Background3D;
00210 
00212 extern RGB Light3D;
00213 
00215 extern RGB Shadow3D;
00216 
00218 extern RGB Border;
00219 
00221 extern RGB Text;
00222 
00224 extern RGB Background;
00225 
00227 extern RGB SelectionBackground;
00228 
00230 extern RGB SelectionForeground;
00231 
00233 extern RGB EditableBackground;
00234 
00236 extern RGB Titlebar;
00237 
00239 extern RGB TitlebarText;
00240 
00242 extern RGB TitlebarInactive;
00243 
00245 extern RGB TitlebarInactiveText;
00246 
00248 static inline RGB rgba(unsigned int r, unsigned int g, unsigned int b, unsigned int a=0) {
00249         return (((r&255)<<RedShift)|((g&255)<<GreenShift)|((b&255)<<BlueShift)|((a&255)<<AlphaShift));
00250 }
00251 
00253 static inline unsigned int R(RGB val) { return ((val&Color::RedMask)>>Color::RedShift); }
00255 static inline unsigned int G(RGB val) { return ((val&Color::GreenMask)>>Color::GreenShift); }
00257 static inline unsigned int B(RGB val) { return ((val&Color::BlueMask)>>Color::BlueShift); }
00259 static inline unsigned int A(RGB val) { return ((val&Color::AlphaMask)>>Color::AlphaShift); }
00260 
00261 }
00262 
00264 enum MouseButton { NoButton, Left, Right, Middle, WheelUp, WheelDown, WheelLeft, WheelRight };
00265 
00267 typedef unsigned int Size;
00268 
00270 typedef uint32_t Char;
00271 
00273 typedef unsigned int Ticks;
00274 
00276 class Key {
00277 public:
00279 
00281         Char character;
00283 
00286         enum Special {
00287                 None,
00288                 F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
00289                 Up, Down, Left, Right, Backspace, Tab, Backtab, Enter, Escape,
00290                 Home, End, PageUp, PageDown, Insert, Delete, Menu,
00291                 Print, Pause, Break, CapsLock, NumLock, ScrollLock,
00292                 Alt, Ctrl, Shift, Windows
00293         } special;
00295         bool shift;
00297         bool ctrl;
00299         bool alt;
00301 
00302         bool windows;
00303 
00305         Key(GUI::Char character, Special special, bool shift, bool ctrl, bool alt, bool windows) :
00306                 character(character), special(special),
00307                 shift(shift), ctrl(ctrl), alt(alt), windows(windows) {}
00308 };
00309 
00310 class Drawable;
00311 class String;
00312 
00330 template <typename STR> class NativeString {
00331 protected:
00332         friend class String;
00333 
00335         static void getString(String &dest, const STR &src)  { (void)dest; (void)src; STR::_this_string_type_is_not_supported_(); }
00336 
00342         static STR& getNative(const String &src) { (void)src; STR::_this_string_type_is_not_supported_();return*new STR(); }
00343 };
00344 
00345 template <typename STR> class NativeString<STR*> {
00346 protected:
00347         friend class String;
00348         static void getString(String &dest, const STR *src);
00349         static STR* getNative(const String &src);
00350 };
00351 
00352 template <typename STR, Size N> class NativeString<STR[N]> : public NativeString<STR*> {};
00353 template <typename STR, Size N> class NativeString<const STR[N]> : public NativeString<STR*> {};
00354 template <typename STR> class NativeString<const STR*> : public NativeString<STR*> {};
00355 
00357 struct ltvoid { bool operator()(const void* s1, const void* s2) const { return s1 < s2; } };
00358 
00359 class Refcount {
00360 public:
00361     /* NTS: Refcount starts at zero because there's so much of this damn code that expects to
00362      *      create UI elements with just "new Window blah blah" and for the class to delete it.
00363      *      This makes the transition to proper refcounting less painful and more gradual. */
00364     Refcount() : _refcount(0) { }
00365     virtual ~Refcount() {
00366         if (_refcount != 0) fprintf(stderr,"WARNING: GUI_TK::Refcount object %p refcount is nonzero (%d) on destructor\n",(void*)this,_refcount);
00367     }
00368 public:
00369     int addref(void) {
00370         return ++_refcount;
00371     }
00372     int release(void) {
00373         int ref = --_refcount;
00374 
00375         if (ref < 0) fprintf(stderr,"WARNING: GUI_TK::Refcount object %p refcount is negative (%d) after release\n",(void*)this,_refcount);
00376         if (ref == 0) delete this;
00377 
00378         return ref;
00379     }
00380 private:
00381     volatile int _refcount;
00382 };
00383 
00384 template <class C> class RefcountAuto : public Refcount {
00385 public:
00386     RefcountAuto() : Refcount(), _ptr(NULL) { }
00387     RefcountAuto(C * const np) : _ptr(np) { if (_ptr != NULL) _ptr->addref(); }
00388     virtual ~RefcountAuto() { if (_ptr != NULL) _ptr->release(); }
00389 public:
00390     C* operator=(C * const np) {
00391         if (_ptr != np) {
00392             C* _old = _ptr;
00393             _ptr = np;
00394             if (_ptr != NULL) _ptr->addref();
00395             if (_old != NULL) _old->release();
00396         }
00397 
00398         return _ptr;
00399     }
00400     bool operator==(const C * const np) const {
00401         return (_ptr == np);
00402     }
00403     bool operator!=(const C * const np) const {
00404         return !(*this == np);
00405     }
00406     bool operator!() const { /* ex: if (!ptr) ... equiv. if (ptr == NULL) */
00407         return (_ptr == NULL);
00408     }
00409     C* getptr(void) const {
00410         return _ptr;
00411     }
00412     C& operator*(void) const {
00413         return *_ptr;
00414     }
00415     C* operator->(void) const {
00416         return _ptr;
00417     }
00418 private:
00419     C*              _ptr;
00420 };
00421 
00432 class String : public std::vector<Char> {
00433 protected:
00434         template <typename STR> friend class NativeString;
00436         class Native { public: virtual ~Native() {}; };
00438         template <typename STR> class NativeArray: public Native {
00439                 STR *data;
00440         public:
00441                 NativeArray(STR *data) : data(data) {}
00442                 virtual ~NativeArray() { delete[] data; }
00443         };
00444         template <typename STR> class NativeObject: public Native {
00445                 STR *data;
00446         public:
00447                 NativeObject(STR *data) : data(data) {}
00448                 virtual ~NativeObject() { delete data; }
00449         };
00450 
00451 private:
00453         mutable std::map<const class std::type_info *, Native *, ltvoid> strings;
00454 
00455 protected:
00457         void addNative(Native *dest) const {
00458                 const class std::type_info &type = typeid(dest);
00459                 if (strings[&type] != NULL) delete strings[&type];
00460                 strings[&type] = dest;
00461         }
00462 
00463 public:
00465         template <typename STR> String(const STR& src) { NativeString<STR>::getString(*this, src); }
00466 
00468         template <class InputIterator> String(InputIterator a, InputIterator b) : std::vector<Char>(a,b) {}
00469 
00471         String(const String &src) : std::vector<Char>(src), strings() {};
00472 
00474         String() { }
00475 
00477         ~String() {
00478                 for (std::map<const class std::type_info *, Native *, ltvoid>::iterator i = strings.begin(); i != strings.end(); ++i)
00479                         delete (*i).second;
00480         };
00481 
00483 
00485         template <typename T> operator T() const { return NativeString<T>::getNative(*this); }
00486 
00488         template <typename T> bool operator==(const T &src) const { return *this == String(src); }
00490         bool operator==(const String &src) const { return *(std::vector<Char>*)this == src; }
00491 
00493         template <typename T> bool operator!=(const T &src) const { return *this != String(src); }
00495         bool operator!=(const String &src) const { return *(std::vector<Char>*)this != src; }
00496 
00498     String& operator=(const String&) = default;
00499 };
00500 
00501 template <typename STR> void NativeString<STR*>::getString(String &dest, const STR* src) {
00502         Size strlen = 0;
00503         while (src[strlen]) strlen++;
00504         dest.resize(strlen);
00505         for (strlen = 0; src[(unsigned int)strlen]; strlen++) dest[(unsigned int)strlen] = (unsigned int)(sizeof(STR)==1?(unsigned char)src[strlen]:sizeof(STR)==2?(unsigned short)src[strlen]:src[strlen]);
00506 }
00507 
00508 template <typename STR> STR* NativeString<STR*>::getNative(const String &src) {
00509         Size strlen = (Size)src.size();
00510         STR* dest = new STR[strlen+1];
00511         dest[strlen] = 0;
00512         for (; strlen > 0; strlen--) dest[strlen-1] = src[strlen-1];
00513         src.addNative(new String::NativeArray<const STR>(dest));
00514         return dest;
00515 }
00516 
00517 template <> class NativeString<std::string*> {
00518 protected:
00519         friend class String;
00520         static void getString(String &dest, const std::string *src) {
00521                 Size strlen = (Size)src->length();
00522                 dest.resize(strlen);
00523                 for (Size i = 0; i< strlen; i++) dest[i] = (unsigned int)((*src)[i]);
00524         }
00525         static std::string* getNative(const String &src) {
00526                 Size strlen = (Size)src.size();
00527                 std::string* dest = new std::string();
00528                 for (Size i = 0; i < strlen; i++) dest->append(1,src[i]);
00529                 src.addNative(new String::NativeObject<std::string>(dest));
00530                 return dest;
00531         }
00532 };
00533 
00534 template <> class NativeString<const std::string*> : public NativeString<std::string*> {};
00535 
00536 template <> class NativeString<std::string> {
00537 protected:
00538         friend class String;
00539         static void getString(String &dest, const std::string &src) {
00540                 Size strlen = (Size)src.length();
00541                 dest.resize(strlen);
00542                 for (Size i = 0; i< strlen; i++) dest[i] = (unsigned int)src[i];
00543         }
00544         static std::string& getNative(const String &src) {
00545                 Size strlen = (Size)src.size();
00546                 std::string* dest = new std::string();
00547                 for (Size i = 0; i < strlen; i++) dest->append(1,src[i]);
00548                 src.addNative(new String::NativeObject<std::string>(dest));
00549                 return *dest;
00550         }
00551 };
00552 
00553 template <> class NativeString<const std::string> : public NativeString<std::string> {};
00554 
00555 class ToplevelWindow;
00556 class Menu;
00557 class TransientWindow;
00558 class Screen;
00559 class Window;
00560 
00562 struct Window_Callback {
00563 public:
00565                 virtual void windowMoved(Window *win, int x, int y) = 0;
00566                 virtual ~Window_Callback() {}
00567 };
00568 
00569 
00579 class Window : public Refcount {
00580 protected:
00581         friend class ToplevelWindow;
00582         friend class TransientWindow;
00583     friend class WindowInWindow;
00584         friend class Menu;
00585 
00587         int width;
00589         int height;
00591         int x;
00593         int y;
00594 
00596         bool dirty;
00597 
00599         bool visible;
00600 
00602     bool tabbable;
00603 
00605         Window *const parent;
00606 
00608 
00609         Window  *mouseChild;
00610 
00612     bool transient;
00613 
00615     bool toplevel;
00616 
00618     bool mouse_in_window;
00619 public:
00621     bool first_tabbable = false;
00622 
00624     bool last_tabbable = false;
00625 protected:
00627 
00629         std::list<Window *> children;
00630 
00632         std::list<Window_Callback *> movehandlers;
00633 
00635         virtual void addChild(Window *child);
00636 
00638         virtual void removeChild(Window *child);
00639 
00641         void setDirty() { if (dirty) return; dirty = true; if (parent != NULL) parent->setDirty(); };
00642 
00644         virtual void setClipboard(const String &s) { parent->setClipboard(s); };
00645 
00647         virtual const String& getClipboard() { return parent->getClipboard(); };
00648 
00650         Window();
00651 
00653         virtual void focusChanged(bool gained) {
00654                 if (children.size() > 0) children.back()->focusChanged(gained);
00655         }
00656 
00657 public:
00658 
00660         void addWindowHandler(Window_Callback *handler) { movehandlers.push_back(handler); }
00661 
00663         void removeWindowHandler(Window_Callback *handler) { movehandlers.remove(handler); }
00664 
00666         Window(Window *parent, int x, int y, int w, int h);
00667 
00669         virtual ~Window();
00670 
00672 
00674         virtual void resize(int w, int h);
00676         virtual int getWidth() const { return width; }
00678         virtual int getHeight() const { return height; }
00679 
00681 
00683         virtual void move(int x, int y);
00685         virtual int getX() const { return x; }
00687         virtual int getY() const { return y; }
00689         virtual int getScreenX() const { return (parent == NULL?0:parent->getScreenX()+x); }
00691         virtual int getScreenY() const { return (parent == NULL?0:parent->getScreenY()+y); }
00692 
00694         virtual void paintAll(Drawable &d) const;
00695 
00697         virtual void paint(Drawable &d) const { (void)d; };
00698 
00700 
00701         virtual void setVisible(bool v) { visible = !!v; parent->setDirty(); if (!visible) mouse_in_window = false; }
00702 
00704         virtual bool isVisible() const { return (!parent || parent->isVisible()) && visible; }
00705 
00707 
00708         Window *getParent() const { return parent; }
00709 
00711         Screen *getScreen();
00712 
00714         virtual bool hasFocus() const { return parent->hasFocus() && *parent->children.rbegin() == this; }
00715 
00717         virtual bool mouseMoved(int x, int y);
00719         virtual void mouseMovedOutside(void);
00721         virtual bool mouseDragged(int x, int y, MouseButton button);
00723         virtual bool mouseDown(int x, int y, MouseButton button);
00725         virtual bool mouseUp(int x, int y, MouseButton button);
00727 
00728         virtual bool mouseClicked(int x, int y, MouseButton button);
00730         virtual bool mouseDoubleClicked(int x, int y, MouseButton button);
00733         virtual bool mouseDownOutside(MouseButton button);
00734 
00736         virtual bool keyDown(const Key &key);
00738         virtual bool keyUp(const Key &key);
00739 
00741 
00742         virtual bool raise() {
00743                 Window *last = parent->children.back();
00744                 for (Window *cur = parent->children.back(); cur != this; cur = parent->children.back()) {
00745                         parent->children.remove(cur);
00746                         parent->children.push_front(cur);
00747                 }
00748                 if (last != this) {
00749                         focusChanged(true);
00750                         last->focusChanged(false);
00751                 }
00752                 parent->setDirty();
00753                 return true;
00754         }
00755 
00757         virtual void lower() {
00758                 parent->children.remove(this);
00759                 parent->children.push_front(this);
00760                 if (this != parent->children.back()) {
00761                         parent->children.back()->focusChanged(true);
00762                         focusChanged(false);
00763                 }
00764                 parent->setDirty();
00765         }
00766 
00768         Window *getChild(int n) {
00769                 for (std::list<Window *>::const_iterator i = children.begin(); i != children.end(); ++i) {
00770                         if ((n--) == 0) return *i;
00771                 }
00772                 return NULL;
00773         }
00774 
00775     unsigned int getChildCount(void) {
00776         return (unsigned int)children.size();
00777     }
00778 
00779 };
00780 
00781 /* Window wrapper to make scrollable regions */
00782 class WindowInWindow : public Window {
00783 protected:
00784     void scrollToWindow(Window *child);
00785 public:
00786         WindowInWindow(Window *parent, int x, int y, int w, int h) :
00787                 Window(parent,x,y,w,h) {}
00788 
00790         virtual bool mouseDragged(int x, int y, MouseButton button);
00792         virtual bool mouseDown(int x, int y, MouseButton button);
00794         virtual bool mouseUp(int x, int y, MouseButton button);
00795 
00797         virtual bool mouseMoved(int x, int y);
00799 
00800         virtual bool mouseClicked(int x, int y, MouseButton button);
00802         virtual bool mouseDoubleClicked(int x, int y, MouseButton button);
00803 
00805         virtual bool keyDown(const Key &key);
00806 
00807         virtual void paintAll(Drawable &d) const;
00808 
00809         virtual void resize(int w, int h);
00810 
00811     virtual void enableScrollBars(bool hs,bool vs);
00812     virtual void enableBorder(bool en);
00813 
00814     bool    hscroll_dragging = false;
00815     bool    vscroll_dragging = false;
00816 
00817     bool    dragging = false;
00818     int     drag_x = 0, drag_y = 0;
00819 
00820     int     scroll_pos_x = 0;
00821     int     scroll_pos_y = 0;
00822     int     scroll_pos_w = 0;
00823     int     scroll_pos_h = 0;
00824 
00825     bool    hscroll = false;
00826     bool    vscroll = false;
00827 
00828     int     hscroll_display_width = 16;
00829     int     vscroll_display_width = 16;
00830 
00831     bool    border = false;
00832 };
00833 
00847 class Screen : public Window {
00848 protected:
00850         Drawable *const buffer;
00851     bool buffer_i_alloc;
00852 
00854         String clipboard;
00855 
00857         MouseButton button = (MouseButton)0;
00858 
00860         virtual void rgbToSurface(RGB color, void **pixel) = 0;
00861 
00863         virtual RGB surfaceToRGB(void *pixel) = 0;
00864 
00866         Screen(Size width, Size height);
00867 
00869         Screen(Drawable *d);
00870 
00871 public:
00873         virtual ~Screen();
00874 
00876         template <typename STR> void setClipboard(const STR s) { this->setClipboard(String(s)); }
00877 
00879         virtual void setClipboard(const String &s) { clipboard = s; }
00880 
00882         virtual const String& getClipboard() { return clipboard; }
00883 
00885         virtual void resize(int w, int h);
00886 
00888         virtual void move(int x, int y);
00889 
00891         virtual bool hasFocus() const { return true; }
00892 
00894 
00898         Ticks update(void *surface, Ticks ticks = 1);
00899 
00901         virtual void paint(Drawable &d) const;
00902 };
00903 
00904 class Timer;
00905 
00907 struct Timer_Callback {
00908 public:
00910 
00915                 virtual Ticks timerExpired(Ticks time) = 0;
00916                 virtual ~Timer_Callback() {}
00917 };
00918 
00928 class Timer {
00929 protected:
00931         static Ticks ticks;
00932 
00934         struct ltuint { bool operator()(Ticks i1, Ticks i2) const {
00935                 return (i1 < i2);
00936         } };
00937 
00939         static std::multimap<Ticks,Timer_Callback*,ltuint> timers;
00940 
00941 public:
00943         static void check(Ticks ticks);
00944         static void check_to(Ticks ticks);
00945 
00947 
00948         static void add(Timer_Callback *cb, const Ticks ticks) { timers.insert(std::pair<const Ticks,Timer_Callback *>(ticks+Timer::ticks,cb)); }
00949 
00950         static void remove(const Timer_Callback *const timer);
00951 
00953         static Ticks now() { return ticks; }
00954 
00956         static Ticks next();
00957 };
00958 
00959 
00965 class ScreenRGB32le : public Screen {
00966 protected:
00968         virtual void rgbToSurface(RGB color, void **pixel) { RGB **p = (RGB **)pixel; **p = color; (*p)++; };
00969 
00971         virtual RGB surfaceToRGB(void *pixel) { return *(RGB*)pixel; };
00972 public:
00973         ScreenRGB32le(Size width, Size height) : Screen(width,height) {};
00974 
00975         virtual void paint(Drawable &d) const;
00976 };
00977 
00978 
00979 #ifdef SDL_MAJOR_VERSION
00980 
00994 class ScreenSDL : public Screen {
00995 protected:
00997         virtual void rgbToSurface(RGB color, void **pixel) { (void)color; (void)pixel; };
00998 
01000         virtual RGB surfaceToRGB(void *pixel) { (void)pixel; return 0; };
01001 
01003         SDL_Surface *surface;
01004         Uint32 start_abs_time,current_abs_time,current_time;
01005 
01007         int downx, downy;
01008 
01010         Ticks lastclick,lastdown;
01011 
01012 public:
01013 
01019         ScreenSDL(SDL_Surface *surface);
01020     virtual ~ScreenSDL();
01021 
01028         void setSurface(SDL_Surface *surface) { this->surface = surface; }
01029 
01031         SDL_Surface *getSurface() { return surface; }
01032 
01034         virtual void paint(Drawable &d) const;
01035 
01037         Ticks update(Ticks ticks);
01038 
01040         bool event(const SDL_Event *ev) { return event(*ev); }
01041 
01042         void watchTime();
01043         Uint32 getTime() { return current_time; }
01044 
01046         bool event(const SDL_Event& event);
01047 };
01048 #endif
01049 
01050 class Font;
01051 
01070 class Drawable {
01071 protected:
01072         friend Ticks Screen::update(void *, Ticks);
01074         RGB *const buffer;
01076         const int width;
01078         const int height;
01080         const bool owner;
01081 
01083         RGB color;
01085         const Font *font;
01087         int lineWidth;
01088 
01090         const int tx;
01092         const int ty;
01094         const int cx;
01096         const int cy;
01098         const int cw;
01100         const int ch;
01102         const int fw;
01104         const int fh;
01105 
01107         int x;
01109         int y;
01110 
01111 public:
01113 
01114         Drawable(int w, int h, RGB clear = Color::Transparent);
01115 
01117 
01121         Drawable(Drawable &src, RGB clear = 0);
01122 
01124         Drawable(Drawable &src, int x, int y, int w, int h);
01125 
01127         virtual ~Drawable();
01128 
01130         void clear(RGB clear = Color::Transparent);
01131 
01133 
01137         void setColor(RGB c) { color = c; };
01139         RGB getColor() { return color; };
01140 
01142         void setFont(const Font *f) { font = f; };
01144         const Font *getFont() { return font; };
01145 
01147         void setLineWidth(int w) { lineWidth = w; };
01149         int getLineWidth() { return lineWidth; };
01150 
01152         void gotoXY(int x, int y) { this->x = x; this->y = y; };
01154         int getX() { return x; }
01156         int getY() { return y; }
01157 
01159         int getClipX() { return cx; }
01161         int getClipY() { return cy; }
01163         int getClipWidth() { return cw; }
01165         int getClipHeight() { return ch; }
01166 
01168         void drawPixel() { if (x >= cx && x < cw && y >= cy && y < ch) buffer[x+tx+(y+ty)*width] = color; };
01170         void drawPixel(int x, int y) { gotoXY(x,y); drawPixel(); };
01171 
01173         RGB getPixel() { if (x >= cx && x < cw && y >= cy && y < ch) return buffer[x+tx+(y+ty)*width]; return Color::Transparent; };
01175         RGB getPixel(int x, int y) { gotoXY(x,y); return getPixel(); };
01176 
01178         void drawLine(int x2, int y2);
01180         void drawLine(int x1, int y1, int x2, int y2) { gotoXY(x1,y1); drawLine(x2,y2); };
01181 
01183         void drawDotLine(int x2, int y2);
01185         void drawDotLine(int x1, int y1, int x2, int y2) { gotoXY(x1,y1); drawDotLine(x2,y2); };
01186 
01188 
01189         void drawCircle(int d);
01191 
01192         void drawCircle(int x, int y, int d) { gotoXY(x, y); drawCircle(d); };
01193 
01195 
01196         void drawRect(int w, int h);
01198 
01199         void drawRect(int x, int y, int w, int h) { gotoXY(x, y); drawRect(w, h); };
01200 
01202 
01203         void drawDotRect(int w, int h);
01205 
01206         void drawDotRect(int x, int y, int w, int h) { gotoXY(x, y); drawDotRect(w, h); };
01207 
01209 
01211         void fill();
01213 
01214         void fill(int x, int y) { gotoXY(x,y); fill(); };
01215 
01217 
01218         void fillCircle(int d);
01220 
01221         void fillCircle(int x, int y, int d) { gotoXY(x, y); fillCircle(d); };
01222 
01224 
01225         void fillRect(int w, int h);
01227 
01228         void fillRect(int x, int y, int w, int h) { gotoXY(x, y); fillRect(w, h); };
01229 
01231 
01237         void drawText(const String& text, bool interpret = true, Size start = 0, Size len = (Size)-1);
01238 
01240 
01241         template <typename STR> void drawText(int x, int y, const STR text, bool interpret, Size start, Size len = (Size)-1) { gotoXY(x,y); drawText(String(text), interpret, start, len); }
01243 
01245         void drawText(const Char c, bool interpret = false);
01247 
01248         void drawText(int x, int y, const Char c, bool interpret = false) { gotoXY(x,y); drawText(c, interpret); }
01249 
01251 
01255         void drawDrawable(Drawable &d, unsigned char alpha = 1);
01257 
01259         void drawDrawable(int x, int y, Drawable &d, unsigned char alpha = 1) { gotoXY(x,y); drawDrawable(d, alpha); }
01260 
01261 };
01262 
01288 class Font {
01289 protected:
01290         friend void Drawable::drawText(const Char c, bool interpret);
01291         friend void Drawable::drawText(const String& s, bool interpret, Size start, Size len);
01292 
01294         struct ltstr { bool operator()(const char* s1, const char* s2) const {
01295                 return strcmp(s1, s2) < 0;
01296         } };
01298         static std::map<const char *,Font *,ltstr> registry;
01299 
01301         Font() {};
01302 
01304 
01306         virtual void drawChar(Drawable *d, const Char c) const = 0;
01307 
01309 
01310         virtual void drawString(Drawable *d, const String &s, Size start, Size len) const {
01311                 if (len > s.size()-start) len = (Size)(s.size()-start);
01312                 len += start;
01313                 while (start < len) drawChar(d,s[start++]);
01314         }
01315 
01316 public:
01318 
01319         static const Font *getFont(const char *name) {
01320                 std::map<const char *,Font *,ltstr>::iterator i = registry.find(name);
01321                 if (i == registry.end()) return(strcmp(name,"default")?getFont("default"):NULL);
01322                 return (*i).second;
01323         }
01324 
01325         static void registry_freeall() {
01326                 std::map<const char *,Font *,ltstr>::iterator it;
01327 
01328                 while ((it=registry.begin()) != registry.end()) {
01329                         delete it->second;
01330                         it->second = NULL;
01331                         registry.erase(it);
01332                 }
01333         }
01334 
01336 
01338         static void addFont(const char *name, Font *font) {
01339                 std::map<const char *,Font *,ltstr>::iterator i = registry.find(name);
01340                 if (i != registry.end()) delete (*i).second;
01341                 registry[name] = font;
01342         }
01343 
01344         virtual ~Font() {};
01345 
01347         virtual int getHeight() const = 0;
01348 
01350         virtual int getAscent() const = 0;
01351 
01353         template <typename STR> int getWidth(const STR s, Size start = 0, Size len = (Size)-1) const {
01354                 return this->getWidth(String(s), start, len);
01355         }
01356 
01358         virtual int getWidth(Char c = 'M') const = 0;
01359 
01361 
01362         virtual int getWidth(const String &s, Size start = 0, Size len = (Size)-1) const {
01363                 int width = 0;
01364                 if ((size_t)start+len > s.size()) len = (Size)(s.size()-start);
01365                 while (len--) width += getWidth(s[start++]);
01366                 return width;
01367         }
01368 
01370         enum SpecialChar { CR = '\r', LF = '\n', BS = '\b', Tab = '\t', Space = ' ', ESC = 27 };
01371 
01373         virtual SpecialChar toSpecial(Char c) const { return (SpecialChar)(c<255?c:255); }
01374 
01376         virtual Char fromSpecial(SpecialChar c) const { return c; }
01377 };
01378 
01385 class BitmapFont : public Font {
01386 protected:
01388         const unsigned char *const bitmap;
01389 
01391         const int width;
01392 
01394         const int height;
01395 
01397         const int ascent;
01398 
01400         const int *const widths;
01401 
01403 
01404         const int *const ascents;
01405 
01407         const bool background_set;
01408 
01410         const int col_step;
01411 
01413         const int row_step;
01414 
01416 
01417         const int character_step;
01418 
01420         const unsigned char *const*const char_position;
01421 
01423 
01424         const SpecialChar *const special;
01425 
01427         const bool owner;
01428 
01430         const Char last;
01431 
01433 
01435         virtual void drawChar(Drawable *d, const Char c) const;
01436 
01437 public:
01439 
01442         BitmapFont(const unsigned char *data, int height, int ascent, bool owner = false,
01443                 int width = 8, bool background_set = false,
01444                 int col_step = -1, int row_step = 8, int character_step = 0, Char last = 256,
01445                 const int *widths = NULL, const int *ascents = NULL,
01446                 const unsigned char *const* char_position = NULL,
01447                 const SpecialChar *special = NULL);
01448 
01449         virtual ~BitmapFont();
01450 
01452         virtual int getHeight() const { return height; };
01453 
01455         virtual int getAscent() const { return ascent; };
01456 
01458         virtual int getWidth(Char c = 'M') const { return (widths != NULL?widths[c]:width); };
01459 
01461         virtual SpecialChar toSpecial(Char c) const { return (special != NULL?special[c]:Font::toSpecial(c)); }
01462 
01464         virtual Char fromSpecial(SpecialChar c) const { if (special == NULL) return Font::fromSpecial(c); Char i = 0; while(special[i] != c) i++; return i; }
01465 
01466 };
01467 
01468 class ActionEventSource;
01470 struct ActionEventSource_Callback {
01471 public:
01473 
01474                 virtual void actionExecuted(ActionEventSource *source, const String &arg) = 0;
01475                 virtual ~ActionEventSource_Callback() {}
01476 };
01477 
01479 
01484 class ActionEventSource {
01485 protected:
01487         std::list<ActionEventSource_Callback *> actionHandlers;
01488 
01490 
01492         String name;
01493 
01494 public:
01496         template <typename STR> ActionEventSource(const STR name) : name(String(name)) { }
01497 
01499         virtual ~ActionEventSource() {}
01500 
01502         void addActionHandler(ActionEventSource_Callback *handler) { actionHandlers.push_back(handler); }
01503 
01505         void removeActionHandler(ActionEventSource_Callback *handler) { actionHandlers.remove(handler); }
01506 
01508         template <typename STR> void setName(const STR name) { this->name = String(name); }
01509 
01511         const String &getName() const { return name; }
01512 
01514         void executeAction(const String &arg) {
01515                 std::list<ActionEventSource_Callback*>::iterator i = actionHandlers.begin();
01516                 bool end = (i == actionHandlers.end());
01517                 while (!end) {
01518                         ActionEventSource_Callback *c = *i;
01519                         ++i;
01520                         end = (i == actionHandlers.end());
01521                         c->actionExecuted(this,arg);
01522                 }
01523         }
01524 
01526         void executeAction() { executeAction(name); }
01527 };
01528 
01530 class BorderedWindow : public Window {
01531 protected:
01533         int border_left, border_top, border_right, border_bottom;
01534 
01536         BorderedWindow(Window *parent, int x, int y, int w, int h, int bl, int bt, int br, int bb) :
01537                 Window(parent,x,y,w,h), border_left(bl), border_top(bt), border_right(br), border_bottom(bb) {}
01538 
01539 public:
01540         virtual void paintAll(Drawable &d) const;
01541         virtual bool mouseMoved(int x, int y);
01542         virtual bool mouseDown(int x, int y, MouseButton button);
01543         virtual bool mouseDragged(int x, int y, MouseButton button);
01544         virtual bool mouseUp(int x, int y, MouseButton button);
01545         virtual int getScreenX() const { return Window::getScreenX()+border_left; }
01546         virtual int getScreenY() const { return Window::getScreenY()+border_top; }
01547 };
01548 
01550 
01554 class Label : public Window {
01556         const Font *font;
01557 
01559         RGB color;
01560 
01562         String text;
01563 
01565         bool interpret;
01566 
01567 public:
01568 
01569     bool allow_focus = false;
01570 
01572 
01573         template <typename STR> Label(Window *parent, int x, int y, const STR text, int width = 0, const Font *font = Font::getFont("default"), RGB color = Color::Text) :
01574                 Window(parent, x, y, (width?width:1), 1), font(font), color(color), text(text), interpret(width != 0)
01575         { Label::resize(); tabbable = false; }
01576 
01578         template <typename STR> void setText(const STR text) { this->text = text; resize(); }
01580         const String& getText() { return text; }
01581 
01583         void setFont(const Font *font) { this->font = font; resize(); }
01585         const Font *getFont() { return font; }
01586 
01588         void setColor(const RGB color) { this->color = color; resize(); }
01590         RGB getColor() { return color; }
01591 
01593         virtual void resize(int w = -1, int h = -1) {
01594         (void)h;//UNUSED
01595                 if (w == -1) w = (interpret?getWidth():0);
01596                 else interpret = (w != 0);
01597                 Drawable d((w?w:1), 1);
01598                 d.setFont(font);
01599                 d.drawText(0, font->getAscent(), text, interpret, 0);
01600                 if (interpret) Window::resize(w, d.getY()-font->getAscent()+font->getHeight());
01601                 else Window::resize(d.getX(), font->getHeight());
01602         }
01603 
01605         virtual bool hasFocus() const { return allow_focus && Window::hasFocus(); }
01606 
01608         virtual void paint(Drawable &d) const { d.setColor(color); d.drawText(0, font->getAscent(), text, interpret, 0); if (hasFocus()) d.drawDotRect(0,0,width-1,height-1); }
01609 
01610         virtual bool raise() { return false; }
01611 };
01612 
01613 
01615 
01618 class Input : public Window, public Timer_Callback, public ActionEventSource {
01619 protected:
01621         String text;
01622 
01624         Size pos;
01625 
01627         Size lastpos;
01628 
01630         int posx, posy;
01631 
01633         Size start_sel, end_sel;
01634 
01636         bool blink;
01637 
01639         bool insert;
01640 
01642         bool multi;
01643 
01645         int offset;
01646 
01648     bool enable_tab_input;
01649 
01651         void checkOffset() {
01652                 if (lastpos == pos) return;
01653                 const Font *f = Font::getFont("input");
01654                 if (multi) {
01655                         Drawable d(width-6,1);
01656                         d.setFont(f);
01657                         d.drawText(0, 0, text, multi, 0, pos);
01658                         posy = d.getY();
01659                         posx = d.getX();
01660                         if (posy-offset > height-8-f->getHeight()) offset = posy-height+8+f->getHeight();
01661                         if (posy-offset < 0) offset = posy;
01662                 } else {
01663                         posy = 0;
01664                         posx = f->getWidth(text,0,pos);
01665                         if (f->getWidth(text,0,pos+1)-offset > width-10) offset = f->getWidth(text,0,pos+1)-width+10;
01666                         if (f->getWidth(text,0,(pos>0?pos-1:0))-offset < 0) offset = f->getWidth(text,0,(pos>0?pos-1:0));
01667                 }
01668                 lastpos = pos;
01669                 setDirty();
01670         }
01671 
01672 public:
01674         Input(Window *parent, int x, int y, int w, int h = 0) :
01675                 Window(parent,x,y,w,(h?h:Font::getFont("input")->getHeight()+10)), ActionEventSource("GUI::Input"),
01676                 text(""), pos(0), lastpos(0), posx(0), posy(0), start_sel(0), end_sel(0), blink(true), insert(true), multi(h != 0), offset(0), enable_tab_input(false)
01677         { Timer::add(this,30); }
01678 
01679         ~Input() {
01680                 Timer::remove(this);
01681         }
01682 
01684         virtual void paint(Drawable &d) const;
01685 
01687         void clearSelection() {
01688                 text.erase(text.begin()+int(pos = imin(start_sel,end_sel)),text.begin()+int(imax(start_sel,end_sel)));
01689                 start_sel = end_sel = pos;
01690         }
01691 
01693         void copySelection() {
01694                 setClipboard(String(text.begin()+int(imin(start_sel,end_sel)),text.begin()+int(imax(start_sel,end_sel))));
01695         }
01696 
01698         void cutSelection() {
01699                 setClipboard(String(text.begin()+int(imin(start_sel,end_sel)),text.begin()+int(imax(start_sel,end_sel))));
01700                 clearSelection();
01701         }
01702 
01704         void pasteSelection() {
01705                 String c = getClipboard();
01706                 clearSelection();
01707                 text.insert(text.begin()+int(pos),c.begin(),c.end());
01708                 start_sel = end_sel = pos += (Size)c.size();
01709         }
01710 
01712         Size findPos(int x, int y);
01713 
01715         template <typename STR> void setText(const STR text) { this->text = text; setDirty(); }
01717         const String& getText() { return text; };
01718 
01720         virtual bool keyDown(const Key &key);
01721 
01723         virtual bool mouseDown(int x, int y, MouseButton button);
01724 
01726         virtual bool mouseDragged(int x, int y, MouseButton button);
01727 
01729         virtual Ticks timerExpired(Ticks time)
01730         { (void)time; blink = !blink; setDirty(); return 30; }
01731 
01733         virtual void posToEnd(void);
01734 };
01735 
01736 class ToplevelWindow;
01738 struct ToplevelWindow_Callback {
01739 public:
01741 
01744                 virtual bool windowClosing(ToplevelWindow *win) = 0;
01745 
01747 
01751                 virtual void windowClosed(ToplevelWindow *win) = 0;
01752                 virtual ~ToplevelWindow_Callback() {}
01753 };
01754 
01756 class ToplevelWindow : public BorderedWindow, public ActionEventSource_Callback {
01757 protected:
01759         String title;
01760 
01762         int dragx, dragy;
01763 
01765         std::list<ToplevelWindow_Callback *> closehandlers;
01766 
01768         Menu *systemMenu;
01769 
01770 public:
01772         template <typename STR> ToplevelWindow(Screen *parent, int x, int y, int w, int h, const STR title);
01773 
01775         ~ToplevelWindow() {
01776                 std::list<ToplevelWindow_Callback*>::iterator i = closehandlers.begin();
01777                 bool end = (i == closehandlers.end());
01778                 while (!end) {
01779                         ToplevelWindow_Callback *c = *i;
01780                         ++i;
01781                         end = (i == closehandlers.end());
01782                         c->windowClosed(this);
01783                 }
01784         }
01785 
01787         virtual void actionExecuted(ActionEventSource *src, const String &item) {
01788         (void)src;
01789                 if (item == String("Close")) close();
01790         }
01791 
01793         void addCloseHandler(ToplevelWindow_Callback *handler) { closehandlers.push_back(handler); }
01794 
01796         void removeCloseHandler(ToplevelWindow_Callback *handler) { closehandlers.remove(handler); }
01797 
01798         virtual void paint(Drawable &d) const;
01799         virtual bool mouseDown(int x, int y, MouseButton button);
01800         virtual bool mouseDoubleClicked(int x, int y, MouseButton button);
01801         virtual bool mouseUp(int x, int y, MouseButton button) {
01802                 if (button == Left && dragx >= 0 && dragy >= 0) {
01803                         dragx = dragy = -1;
01804                         return true;
01805                 }
01806                 BorderedWindow::mouseUp(x,y,button);
01807                 return true;
01808         }
01809         virtual bool mouseDragged(int x, int y, MouseButton button) {
01810                 if (button == Left && dragx >= 0 && dragy >= 0) {
01811                         move(x-dragx+this->x,y-dragy+this->y);
01812                         return true;
01813                 }
01814                 BorderedWindow::mouseDragged(x,y,button);
01815                 return true;
01816         }
01817         virtual bool mouseMoved(int x, int y) {
01818                 BorderedWindow::mouseMoved(x,y);
01819                 return true;
01820         }
01821 
01823         virtual bool raise() {
01824                 Window *last = parent->children.back();
01825                 parent->children.remove(this);
01826                 parent->children.push_back(this);
01827                 if (last != this) {
01828                         focusChanged(true);
01829                         last->focusChanged(false);
01830                 }
01831                 return true;
01832         }
01833 
01835         template <typename STR> void setTitle(const STR title) { this->title = title; setDirty(); }
01837         const String& getTitle() { return title; }
01838 
01840         void close() {
01841                 bool doit = true;
01842                 std::list<ToplevelWindow_Callback*>::iterator i = closehandlers.begin();
01843                 bool end = (i == closehandlers.end());
01844                 while (!end) {
01845                         ToplevelWindow_Callback *c = *i;
01846                         ++i;
01847                         end = (i == closehandlers.end());
01848                         doit = doit && c->windowClosing(this);
01849                 }
01850                 if (doit) delete this;
01851         }
01852 };
01853 
01855 
01869 class TransientWindow : public Window, Window_Callback, ToplevelWindow_Callback {
01870 protected:
01872         Window *realparent;
01873 
01875         int relx, rely;
01876 
01877 public:
01879         virtual void focusChanged(bool gained) {
01880                 Window::focusChanged(gained);
01881                 if (isVisible() && !gained) {
01882                         if (realparent->hasFocus()) raise();
01883                         else setVisible(false);
01884                 }
01885         }
01886 
01888         void windowClosed(ToplevelWindow *win) {
01889         (void)win;
01890                 delete this;
01891         }
01892 
01894         bool windowClosing(ToplevelWindow *win) { (void)win; return true; }
01895 
01897 
01899         TransientWindow(Window *parent, int x, int y, int w, int h) :
01900                 Window(parent->getScreen(),x+parent->getScreenX(),y+parent->getScreenY(),w,h),
01901                 realparent(parent), relx(x), rely(y) {
01902                 Window *p = realparent, *last = NULL, *last2 = NULL;
01903                 while (p != NULL) {
01904                         p->addWindowHandler(this);
01905                         last2 = last;
01906                         last = p;
01907                         p = p->getParent();
01908                 }
01909         transient = true;
01910                 dynamic_cast<ToplevelWindow *>(last2)->addCloseHandler(this);
01911         }
01912 
01913         ~TransientWindow() {
01914                 Window *p = realparent, *last = NULL, *last2 = NULL;
01915                 while (p != NULL) {
01916                         p->removeWindowHandler(this);
01917                         last2 = last;
01918                         last = p;
01919                         p = p->getParent();
01920                 }
01921                 dynamic_cast<ToplevelWindow *>(last2)->removeCloseHandler(this);
01922          }
01923 
01924         virtual void move(int x, int y) { relx = x; rely = y;
01925                 Window::move(x+realparent->getScreenX(),y+realparent->getScreenY()); }
01926         virtual int getX() const { return x-realparent->getScreenX(); }
01927         virtual int getY() const { return y-realparent->getScreenY(); }
01928         virtual void setVisible(bool v) { if (v) raise(); Window::setVisible(v); }
01929         virtual void windowMoved(Window *src, int x, int y) { (void)src; (void)x; (void)y; move(relx,rely); }
01930     virtual bool mouseDownOutside(MouseButton button) {
01931         (void)button;
01932 
01933         if (visible) {
01934             setVisible(false);
01935             return true;
01936         }
01937 
01938         return false;
01939     }
01940 
01942         virtual bool raise() {
01943                 Window *last = parent->children.back();
01944                 parent->children.remove(this);
01945                 parent->children.push_back(this);
01946                 if (last != this) {
01947                         focusChanged(true);
01948                         last->focusChanged(false);
01949                 }
01950                 return true;
01951         }
01952 
01953 };
01954 
01956 
01965 class Menu : public TransientWindow, public ActionEventSource {
01966 protected:
01968         std::vector<String> items;
01969 
01971     unsigned int rows = 0;
01972     unsigned int columns = 0;
01973     std::vector<unsigned int> colx;
01974 
01976 
01977         int selected;
01978 
01980         bool firstMouseUp;
01981 
01983         Window *mouseTakenFrom;
01984 
01986 
01987         virtual void selectItem(int x, int y) {
01988         unsigned int coli = 0;
01989         int xmin,xmax,ypos = 2;
01990 
01991                 selected = -1;
01992 
01993         xmin = 0;
01994         xmax = width;
01995         if (coli < colx.size()) {
01996             xmin = colx[coli++];
01997             if (coli < colx.size())
01998                 xmax = colx[coli];
01999         }
02000 
02001         // mouse input should select nothing if outside the bounds of this menu
02002         if (x < 3 || x >= (width-3) || y < 2 || y >= (height-2)) return;
02003         selected = 0;
02004 
02005                 const int fheight = Font::getFont("menu")->getHeight()+2;
02006                 std::vector<String>::iterator i;
02007                 for (i = items.begin(); i != items.end(); ++i) {
02008             if ((*i).size() > 0) {
02009                 if (*i == "|") {
02010                     ypos = 2;
02011                     xmin = xmax = width;
02012                     if (coli < colx.size()) {
02013                         xmin = colx[coli++];
02014                         if (coli < colx.size())
02015                             xmax = colx[coli];
02016                     }
02017                 }
02018                 else {
02019                     if (x >= xmin && x < xmax) {
02020                         if (y >= ypos && y < (ypos+fheight))
02021                             break;
02022                     }
02023 
02024                     ypos += fheight;
02025                 }
02026             }
02027             else {
02028                 if (x >= xmin && x < xmax) {
02029                     if (y >= ypos && y < (ypos+12))
02030                         break;
02031                 }
02032 
02033                 ypos += 12;
02034             }
02035 
02036             selected++;
02037                 }
02038 
02039                 if (selected >= 0 && items[(unsigned int)selected].size() == 0) selected = -1;
02040         }
02041 
02042         virtual Size getPreferredWidth() {
02043                 Size width = 0,px = 0;
02044                 const Font *f = Font::getFont("menu");
02045                 std::vector<String>::iterator i;
02046         columns = 1;
02047         colx.clear();
02048         colx.push_back(3+width);
02049         for (i = items.begin(); i != items.end() && y > 0; ++i) {
02050             if (*i == "|") {
02051                 colx.push_back(3+width);
02052                 columns++;
02053                 px = width;
02054             }
02055             else {
02056                 Size newwidth = (unsigned int)f->getWidth(*i) + px + 33;
02057                 if (newwidth > width) width = newwidth;
02058             }
02059                 }
02060                 return width+6;
02061         }
02062 
02063         virtual Size getPreferredHeight() {
02064                 Size height = 0,py = 0,row = 0;
02065                 const Size h = (unsigned int)Font::getFont("menu")->getHeight()+2u;
02066                 std::vector<String>::iterator i;
02067         rows = 0;
02068                 for (i = items.begin(); i != items.end() && y > 0; ++i) {
02069             if (*i == "|") {
02070                 py = 0;
02071                 row = 0;
02072             }
02073             else {
02074                 row++;
02075                 if (rows < row) rows = row;
02076                 py += ((*i).size() > 0?h:12);
02077                 if (height < py) height = py;
02078             }
02079                 }
02080                 return height+6;
02081         }
02082 
02083 public:
02085 
02087         template <typename STR> Menu(Window *parent, int x, int y, const STR name) :
02088                 TransientWindow(parent,x,y,4,4), ActionEventSource(name), selected(-1)
02089                 { Menu::setVisible(false); tabbable = false; }
02090 
02091         ~Menu() {
02092                 Menu::setVisible(false);
02093         }
02094 
02096         virtual void paint(Drawable &d) const;
02097 
02099         virtual bool mouseMoved(int x, int y)  {
02100         if (visible) {
02101             firstMouseUp = false;
02102                 selectItem(x,y);
02103                 return true;
02104         }
02105 
02106         return false;
02107         }
02108 
02109     void mouseMovedOutside(void) {
02110         if (visible && selected >= 0) {
02111             firstMouseUp = false;
02112             selected = -1;
02113             setDirty();
02114         }
02115     }
02116 
02118         virtual bool mouseDragged(int x, int y, MouseButton button)  {
02119         (void)button;//UNUSED   
02120 
02121         if (visible) {
02122             if (x >= 0 && x < width && y >= 0 && y < height)
02123                 firstMouseUp = false;
02124 
02125             selectItem(x,y);
02126             return true;
02127         }
02128 
02129         return false;
02130         }
02131 
02132         virtual bool mouseDown(int x, int y, MouseButton button)  {
02133         (void)button;//UNUSED
02134         (void)x;//UNUSED
02135         (void)y;//UNUSED
02136 
02137         if (visible)
02138             return true;
02139 
02140         return false;
02141     }
02142 
02143         virtual bool mouseDownOutside(MouseButton button) {
02144         (void)button;//UNUSED
02145 
02146         if (visible) {
02147             setVisible(false);
02148             selected = -1;
02149             return true;
02150         }
02151 
02152         return false;
02153     }
02154 
02156         virtual bool mouseUp(int x, int y, MouseButton button)  {
02157         (void)button;//UNUSED
02158 
02159         if (visible) {
02160             selectItem(x,y);
02161             if (firstMouseUp) firstMouseUp = false;
02162             else setVisible(false);
02163             execute();
02164             return true;
02165         }
02166 
02167         return false;
02168     }
02169 
02171         virtual bool keyDown(const Key &key) {
02172         if (visible) {
02173             if (key.special == Key::Up) {
02174                 if (selected == 0)
02175                     selected = (int)items.size() - 1;
02176                 else
02177                     selected--;
02178             }
02179             else if (key.special == Key::Down) {
02180                 if ((size_t)(++selected) == items.size())
02181                     selected = 0;
02182             }
02183             else if (key.special == Key::Enter) { execute(); return true; }
02184             else if (key.special == Key::Escape) { setVisible(false); selected = -1; return true; }
02185             else return true;
02186             if (items[(unsigned int)selected].size() == 0 && items.size() > 1) return keyDown(key);
02187             if (selected < 0) selected = (int)(items.size()-1);
02188             if (selected >= (int)items.size()) selected = 0;
02189             return true;
02190         }
02191 
02192         return false;
02193         }
02194 
02195 
02197         template <typename T> void addItem(const T item) {
02198                 items.push_back(String(item));
02199                 resize((int)getPreferredWidth(),(int)getPreferredHeight());
02200         }
02201 
02203         template <typename T> void removeItem(const T item) {
02204                 const String s(item);
02205                 std::vector<String>::iterator i = items.begin();
02206                 while (i != items.end() && s != (*i)) ++i;
02207                 if (i != items.end()) items.erase(i);
02208                 resize(getPreferredWidth(),getPreferredHeight());
02209         }
02210 
02211         virtual void setVisible(bool v) {
02212         if (!visible && v)
02213             firstMouseUp = true;
02214 
02215         TransientWindow::setVisible(v);
02216                 if (v) {
02217                         parent->mouseChild = this;
02218                         raise();
02219                 }
02220 
02221         // NTS: Do not set selected = -1 here on hide, other code in this C++
02222         //      class relies on calling setVisible() then acting on selection.
02223         //      Unless of course you want to hunt down random and sporadic
02224         //      segfaults. --J.C.
02225         }
02226 
02228         void execute() {
02229                 if (selected >= 0) {
02230                         setVisible(false);
02231 
02232             // FIXME: Some action callbacks including the "Close" command in
02233             //        the system menu will delete this window object before
02234             //        returning to this level in the call stack. Therefore,
02235             //        copy selection index and clear it BEFORE calling the
02236             //        callbacks.
02237             unsigned int sel = (unsigned int)selected;
02238             selected = -1;
02239 
02240                         executeAction(items[sel]);
02241 
02242             // WARNING: Do not access C++ class methods or variables here,
02243             //          the "Close" callback may have deleted this window
02244             //          out from under us! It may happen to work but
02245             //          understand it becomes a use-after-free bug!
02246                 }
02247         }
02248 };
02249 
02251 
02254 class Button : public BorderedWindow, public ActionEventSource {
02255 protected:
02257         bool pressed;
02258 
02259 public:
02261         Button(Window *parent, int x, int y, int w, int h) : BorderedWindow(parent,x,y,w,h,6,5,6,5), ActionEventSource("GUI::Button"), pressed(0) {}
02262 
02264 
02265         template <typename T> Button(Window *parent, int x, int y, const T text, int w = -1, int h = -1);
02266 
02268         virtual void paint(Drawable &d) const;
02269 
02271         virtual bool mouseDown(int x, int y, MouseButton button) {
02272         (void)button;//UNUSED
02273         (void)x;//UNUSED
02274         (void)y;//UNUSED
02275         
02276                 if (button == Left) {
02277                         border_left = 7; border_right = 5; border_top = 7; border_bottom = 3;
02278                         pressed = true;
02279                 }
02280                 return true;
02281         }
02282 
02284         virtual bool mouseUp(int x, int y, MouseButton button)  {
02285         (void)button;//UNUSED
02286         (void)x;//UNUSED
02287         (void)y;//UNUSED
02288         
02289                 if (button == Left) {
02290                         border_left = 6; border_right = 6; border_top = 5; border_bottom = 5;
02291                         pressed = false;
02292                 }
02293                 return true;
02294         }
02295 
02297         virtual bool mouseClicked(int x, int y, MouseButton button) {
02298         (void)button;//UNUSED
02299         (void)x;//UNUSED
02300         (void)y;//UNUSED
02301         
02302                 if (button == Left) {
02303                         executeAction();
02304                         return true;
02305                 }
02306                 return false;
02307         }
02308 
02310         virtual bool keyDown(const Key &key);
02311 
02313         virtual bool keyUp(const Key &key);
02314 
02315 };
02316 
02318 
02324 class Menubar : public Window, public ActionEventSource, ActionEventSource_Callback {
02325 protected:
02327         int selected;
02328 
02330         int lastx;
02331 
02333         std::vector<Menu*> menus;
02334 
02335 public:
02337 
02338         Menubar(Window *parent, int x, int y, int w) : Window(parent,x,y,w,Font::getFont("menu")->getHeight()+5), ActionEventSource("GUI::Menubar"), selected(-1), lastx(0) { tabbable = false; }
02339 
02341         template <typename STR> void addMenu(const STR name) {
02342                 const String n(name);
02343                 menus.push_back(new Menu(this,lastx,height-2,n));
02344                 menus.back()->addActionHandler(this);
02345                 lastx += Font::getFont("menu")->getWidth(n)+14;
02346         }
02347 
02349         template <typename STR> void addItem(int index, const STR name) { menus[(unsigned int)index]->addItem(name); }
02350 
02352         template <typename STR> void removeItem(int index, const STR name) { menus[(unsigned int)index]->removeItem(name); }
02353 
02355         virtual void paint(Drawable &d) const;
02356 
02358         virtual bool mouseDown(int x, int y, MouseButton button) {
02359         (void)button;//UNUSED
02360         (void)y;//UNUSED
02361                 int oldselected = selected;
02362                 if (selected >= 0 && !menus[(unsigned int)selected]->isVisible()) oldselected = -1;
02363                 if (selected >= 0) menus[(unsigned int)selected]->setVisible(false);
02364                 if (x < 0 || x >= lastx) return true;
02365                 for (selected = (int)(menus.size()-1); menus[(unsigned int)selected]->getX() > x; selected--) {};
02366                 if (oldselected == selected) selected = -1;
02367                 else menus[(unsigned int)selected]->setVisible(true);
02368                 return true;
02369         }
02370 
02372         virtual bool keyDown(const Key &key) {
02373         if (key.special == Key::Tab)
02374             return false;
02375 
02376         return true;
02377     }
02378 
02380     virtual bool keyUp(const Key &key) {
02381         if (key.special == Key::Tab)
02382             return false;
02383 
02384         return true;
02385     }
02386 
02387         virtual void actionExecuted(ActionEventSource *src, const String &arg) {
02388                 std::list<ActionEventSource_Callback*>::iterator i = actionHandlers.begin();
02389                 bool end = (i == actionHandlers.end());
02390                 while (!end) {
02391                         ActionEventSource_Callback *c = *i;
02392                         ++i;
02393                         end = (i == actionHandlers.end());
02394                         c->actionExecuted(src,arg);
02395                 }
02396         }
02397 };
02398 
02400 
02403 class Checkbox : public BorderedWindow, public ActionEventSource {
02404 protected:
02406         bool checked;
02407 
02408 public:
02410         Checkbox(Window *parent, int x, int y, int w, int h) : BorderedWindow(parent,x,y,w,h,16,0,0,0), ActionEventSource("GUI::Checkbox"), checked(0) {}
02411 
02413 
02414         template <typename T> Checkbox(Window *parent, int x, int y, const T text, int w = -1, int h = -1);
02415 
02417         virtual void paint(Drawable &d) const;
02418 
02420         virtual void setChecked(bool checked) { this->checked = checked; }
02421 
02423         virtual bool isChecked() { return checked; }
02424 
02426         virtual bool mouseDown(int x, int y, MouseButton button) {
02427         (void)button;//UNUSED
02428         (void)x;//UNUSED
02429         (void)y;//UNUSED        
02430                 checked = !checked;
02431                 return true;
02432         }
02433 
02435         virtual bool mouseUp(int x, int y, MouseButton button)  {
02436         (void)button;//UNUSED
02437         (void)x;//UNUSED
02438         (void)y;//UNUSED        
02439                 execute();
02440                 return true;
02441         }
02442 
02444         virtual bool keyDown(const Key &key);
02445 
02447         virtual bool keyUp(const Key &key);
02448 
02450         virtual void execute() {
02451                 String arg(name);
02452                 if (!checked) arg.insert(arg.begin(),'!');
02453                 executeAction(arg);
02454         }
02455 };
02456 
02457 class Frame;
02458 
02460 
02463 class Radiobox : public BorderedWindow, public ActionEventSource {
02464 protected:
02466         bool checked;
02467 
02468 public:
02470         Radiobox(Frame *parent, int x, int y, int w, int h);
02471 
02473 
02474         template <typename T> Radiobox(Frame *parent, int x, int y, const T text, int w = -1, int h = -1);
02475 
02477         virtual void paint(Drawable &d) const;
02478 
02480         virtual void setChecked(bool checked) { this->checked = checked; }
02481 
02483         virtual bool isChecked() { return checked; }
02484 
02486         virtual bool mouseDown(int x, int y, MouseButton button) {
02487         (void)button;//UNUSED
02488         (void)x;//UNUSED
02489         (void)y;//UNUSED
02490         checked = true;
02491                 return true;
02492         }
02493 
02495         virtual bool mouseUp(int x, int y, MouseButton button)  {
02496         (void)button;//UNUSED
02497         (void)x;//UNUSED
02498         (void)y;//UNUSED
02499                 executeAction();
02500                 return true;
02501         }
02502 
02504         virtual bool keyDown(const Key &key);
02505 
02507         virtual bool keyUp(const Key &key);
02508 };
02509 
02511 
02513 class Frame : public BorderedWindow, public ActionEventSource, protected ActionEventSource_Callback {
02514 protected:
02515         friend class Radiobox;
02516 
02518         int selected;
02519 
02521         String label;
02522 
02524         virtual void actionExecuted(ActionEventSource *src, const String &arg) {
02525         // HACK: Attempting to cast a String to void causes "forming reference to void" errors when building with GCC 4.7
02526         (void)arg.size();//UNUSED
02527                 for (std::list<Window *>::iterator i = children.begin(); i != children.end(); ++i) {
02528                         Radiobox *r = dynamic_cast<Radiobox*>(*i);
02529                         if (r != NULL && src != dynamic_cast<ActionEventSource*>(r)) r->setChecked(false);
02530                 }
02531                 executeAction(src->getName());
02532         }
02533 
02534 public:
02536         Frame(Window *parent, int x, int y, int w, int h) : BorderedWindow(parent,x,y,w,h,5,5,5,5), ActionEventSource("GUI::Frame"), selected(0) {}
02537 
02539         template <typename T> Frame(Window *parent, int x, int y, int w, int h, const T text) :
02540                 BorderedWindow(parent,x,y,w,h,5,Font::getFont("default")->getHeight()+2,5,5),
02541                 ActionEventSource(text), selected(0), label(text) { }
02542 
02544         virtual void paint(Drawable &d) const;
02545 
02546 };
02547 
02549 class MessageBox2 : public GUI::ToplevelWindow {
02550 protected:
02551         Label *message;
02552         Button *close;
02553     WindowInWindow *wiw;
02554 public:
02556         template <typename STR> MessageBox2(Screen *parent, int x, int y, int width, const STR title, const STR text) :
02557                 ToplevelWindow(parent, x, y, width, 1, title) {
02558         wiw = new WindowInWindow(this, 5, 5, width-border_left-border_right-10, 70);
02559                 message = new Label(wiw, 0, 0, text, width-border_left-border_right-10);
02560                 close = new GUI::Button(this, (width-border_left-border_right-70)/2, 10, "Close", 70);
02561                 close->addActionHandler(this);
02562                 setText(text);
02563 
02564                 close->raise(); /* make sure keyboard focus is on the close button */
02565                 this->raise(); /* make sure THIS WINDOW has the keyboard focus */
02566         }
02567 
02569         template <typename STR> void setText(const STR text) {
02570         int sfh;
02571         int msgw;
02572         bool scroll = true;
02573 
02574         msgw = width-border_left-border_right-10;
02575         message->resize(msgw, message->getHeight());
02576                 message->setText(text);
02577 
02578         {
02579             Screen *s = getScreen();
02580             sfh = s->getHeight() - 70 - border_top - border_bottom;
02581             if (sfh > (15+message->getHeight())) {
02582                 sfh = (15+message->getHeight());
02583                 scroll = false;
02584             }
02585         }
02586 
02587         wiw->enableBorder(scroll);
02588         wiw->enableScrollBars(false/*h*/,scroll/*v*/);
02589         if (scroll) {
02590             msgw -= wiw->vscroll_display_width;
02591             msgw -= 2/*border*/;
02592             message->resize(msgw, message->getHeight());
02593         }
02594 
02595                 close->move((width-border_left-border_right-70)/2, sfh);
02596         wiw->resize(width-border_left-border_right-10, sfh-10);
02597                 resize(width, sfh+close->getHeight()+border_bottom+border_top+5);
02598         }
02599 
02600         virtual bool keyDown(const GUI::Key &key) {
02601         if (GUI::ToplevelWindow::keyDown(key)) return true;
02602         return false;
02603     }
02604 
02605         virtual bool keyUp(const GUI::Key &key) {
02606         if (GUI::ToplevelWindow::keyUp(key)) return true;
02607 
02608         if (key.special == GUI::Key::Escape) {
02609             close->executeAction();
02610             return true;
02611         }
02612 
02613         return false;
02614     }
02615 };
02616 
02617 extern int titlebar_y_start;
02618 extern int titlebar_y_stop;
02619 
02620 extern int titlebox_y_start;
02621 extern int titlebox_y_height;
02622 
02623 template <typename STR> ToplevelWindow::ToplevelWindow(Screen *parent, int x, int y, int w, int h, const STR title) :
02624         BorderedWindow(parent, x, y, w, h, 6, titlebar_y_stop, 6, 3), title(title),
02625         dragx(-1), dragy(-1), closehandlers(), systemMenu(new Menu(this,-1,-2,"System Menu")) {
02626 /* If these commands don't do anything, then why have them there?? --J.C. */
02627 #if 0 /* TODO: Allow selective enabling these if the Window object wants us to */
02628         systemMenu->addItem("Move");
02629         systemMenu->addItem("Resize");
02630         systemMenu->addItem("");
02631         systemMenu->addItem("Minimize");
02632         systemMenu->addItem("Maximize");
02633         systemMenu->addItem("Restore");
02634         systemMenu->addItem("");
02635 #endif
02636         systemMenu->addItem("Close");
02637         systemMenu->addActionHandler(this);
02638     toplevel = true;
02639 }
02640 
02641 template <typename STR> Button::Button(Window *parent, int x, int y, const STR text, int w, int h) :
02642         BorderedWindow(parent,x,y,w,h,6,5,6,5), ActionEventSource(text), pressed(0)
02643 {
02644 
02645         Label *l = new Label(this,0,0,text);
02646     l->allow_focus = true;
02647         if (width < 0) resize(l->getWidth()+border_left+border_right+10,height);
02648         if (height < 0) resize(width,l->getHeight()+border_top+border_bottom+6);
02649         l->move((width-border_left-border_right-l->getWidth())/2,
02650                 (height-border_top-border_bottom-l->getHeight())/2);
02651 }
02652 
02653 template <typename STR> Checkbox::Checkbox(Window *parent, int x, int y, const STR text, int w, int h) :
02654         BorderedWindow(parent,x,y,w,h,16,0,0,0), ActionEventSource(text), checked(0)
02655 {
02656         Label *l = new Label(this,0,0,text);
02657         if (width < 0) resize(l->getWidth()+border_left+border_right+4,height);
02658         if (height < 0) resize(width,l->getHeight()+border_top+border_bottom+4);
02659         l->move((width-border_left-border_right-l->getWidth())/2,
02660                 (height-border_top-border_bottom-l->getHeight())/2);
02661 }
02662 
02663 template <typename STR> Radiobox::Radiobox(Frame *parent, int x, int y, const STR text, int w, int h) :
02664         BorderedWindow(parent,x,y,w,h,16,0,0,0), ActionEventSource(text), checked(0)
02665 {
02666         Label *l = new Label(this,0,0,text);
02667         if (width < 0) resize(l->getWidth()+border_left+border_right+4,height);
02668         if (height < 0) resize(width,l->getHeight()+border_top+border_bottom+4);
02669         l->move((width-border_left-border_right-l->getWidth())/2,
02670                 (height-border_top-border_bottom-l->getHeight())/2);
02671         addActionHandler(parent);
02672 }
02673 
02674 }
02675 
02676 #endif