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 Menu;
00584 
00586         int width;
00588         int height;
00590         int x;
00592         int y;
00593 
00595         bool dirty;
00596 
00598         bool visible;
00599 
00601     bool tabbable;
00602 
00604         Window *const parent;
00605 
00607 
00608         Window  *mouseChild;
00609 
00611     bool transient;
00612 
00614     bool toplevel;
00615 
00617     bool mouse_in_window;
00618 
00620 
00622         std::list<Window *> children;
00623 
00625         std::list<Window_Callback *> movehandlers;
00626 
00628         virtual void addChild(Window *child);
00629 
00631         virtual void removeChild(Window *child);
00632 
00634         void setDirty() { if (dirty) return; dirty = true; if (parent != NULL) parent->setDirty(); };
00635 
00637         virtual void setClipboard(const String &s) { parent->setClipboard(s); };
00638 
00640         virtual const String& getClipboard() { return parent->getClipboard(); };
00641 
00643         Window();
00644 
00646         virtual void focusChanged(bool gained) {
00647                 if (children.size() > 0) children.back()->focusChanged(gained);
00648         }
00649 
00650 public:
00651 
00653         void addWindowHandler(Window_Callback *handler) { movehandlers.push_back(handler); }
00654 
00656         void removeWindowHandler(Window_Callback *handler) { movehandlers.remove(handler); }
00657 
00659         Window(Window *parent, int x, int y, int w, int h);
00660 
00662         virtual ~Window();
00663 
00665 
00667         virtual void resize(int w, int h);
00669         virtual int getWidth() const { return width; }
00671         virtual int getHeight() const { return height; }
00672 
00674 
00676         virtual void move(int x, int y);
00678         virtual int getX() const { return x; }
00680         virtual int getY() const { return y; }
00682         virtual int getScreenX() const { return (parent == NULL?0:parent->getScreenX()+x); }
00684         virtual int getScreenY() const { return (parent == NULL?0:parent->getScreenY()+y); }
00685 
00687         virtual void paintAll(Drawable &d) const;
00688 
00690         virtual void paint(Drawable &d) const { (void)d; };
00691 
00693 
00694         virtual void setVisible(bool v) { visible = !!v; parent->setDirty(); if (!visible) mouse_in_window = false; }
00695 
00697         virtual bool isVisible() const { return (!parent || parent->isVisible()) && visible; }
00698 
00700 
00701         Window *getParent() const { return parent; }
00702 
00704         Screen *getScreen();
00705 
00707         virtual bool hasFocus() const { return parent->hasFocus() && *parent->children.rbegin() == this; }
00708 
00710         virtual bool mouseMoved(int x, int y);
00712         virtual void mouseMovedOutside(void);
00714         virtual bool mouseDragged(int x, int y, MouseButton button);
00716         virtual bool mouseDown(int x, int y, MouseButton button);
00718         virtual bool mouseUp(int x, int y, MouseButton button);
00720 
00721         virtual bool mouseClicked(int x, int y, MouseButton button);
00723         virtual bool mouseDoubleClicked(int x, int y, MouseButton button);
00726         virtual bool mouseDownOutside(MouseButton button);
00727 
00729         virtual bool keyDown(const Key &key);
00731         virtual bool keyUp(const Key &key);
00732 
00734 
00735         virtual bool raise() {
00736                 Window *last = parent->children.back();
00737                 for (Window *cur = parent->children.back(); cur != this; cur = parent->children.back()) {
00738                         parent->children.remove(cur);
00739                         parent->children.push_front(cur);
00740                 }
00741                 if (last != this) {
00742                         focusChanged(true);
00743                         last->focusChanged(false);
00744                 }
00745                 parent->setDirty();
00746                 return true;
00747         }
00748 
00750         virtual void lower() {
00751                 parent->children.remove(this);
00752                 parent->children.push_front(this);
00753                 if (this != parent->children.back()) {
00754                         parent->children.back()->focusChanged(true);
00755                         focusChanged(false);
00756                 }
00757                 parent->setDirty();
00758         }
00759 
00761         Window *getChild(int n) {
00762                 for (std::list<Window *>::const_iterator i = children.begin(); i != children.end(); ++i) {
00763                         if (n--) return *i;
00764                 }
00765                 return NULL;
00766         }
00767 
00768 };
00769 
00770 /* Window wrapper to make scrollable regions */
00771 class WindowInWindow : public Window {
00772 protected:
00773 
00774 public:
00775         WindowInWindow(Window *parent, int x, int y, int w, int h) :
00776                 Window(parent,x,y,w,h) {}
00777 
00779         virtual bool mouseDragged(int x, int y, MouseButton button);
00781         virtual bool mouseDown(int x, int y, MouseButton button);
00783         virtual bool mouseUp(int x, int y, MouseButton button);
00784 
00786         virtual bool mouseMoved(int x, int y);
00788 
00789         virtual bool mouseClicked(int x, int y, MouseButton button);
00791         virtual bool mouseDoubleClicked(int x, int y, MouseButton button);
00792 
00793         virtual void paintAll(Drawable &d) const;
00794 
00795         virtual void resize(int w, int h);
00796 
00797     virtual void enableScrollBars(bool hs,bool vs);
00798     virtual void enableBorder(bool en);
00799 
00800     bool    hscroll_dragging = false;
00801     bool    vscroll_dragging = false;
00802 
00803     bool    dragging = false;
00804     int     drag_x,drag_y;
00805 
00806     int     scroll_pos_x = 0;
00807     int     scroll_pos_y = 0;
00808     int     scroll_pos_w = 0;
00809     int     scroll_pos_h = 0;
00810 
00811     bool    hscroll = false;
00812     bool    vscroll = false;
00813 
00814     int     hscroll_display_width = 16;
00815     int     vscroll_display_width = 16;
00816 
00817     bool    border = false;
00818 };
00819 
00833 class Screen : public Window {
00834 protected:
00836         Drawable *const buffer;
00837     bool buffer_i_alloc;
00838 
00840         String clipboard;
00841 
00843         MouseButton button;
00844 
00846         virtual void rgbToSurface(RGB color, void **pixel) = 0;
00847 
00849         virtual RGB surfaceToRGB(void *pixel) = 0;
00850 
00852         Screen(Size width, Size height);
00853 
00855         Screen(Drawable *d);
00856 
00857 public:
00859         virtual ~Screen();
00860 
00862         template <typename STR> void setClipboard(const STR s) { this->setClipboard(String(s)); }
00863 
00865         virtual void setClipboard(const String &s) { clipboard = s; }
00866 
00868         virtual const String& getClipboard() { return clipboard; }
00869 
00871         virtual void resize(int w, int h);
00872 
00874         virtual void move(int x, int y);
00875 
00877         virtual bool hasFocus() const { return true; }
00878 
00880 
00884         Ticks update(void *surface, Ticks ticks = 1);
00885 
00887         virtual void paint(Drawable &d) const;
00888 };
00889 
00890 class Timer;
00891 
00893 struct Timer_Callback {
00894 public:
00896 
00901                 virtual Ticks timerExpired(Ticks time) = 0;
00902                 virtual ~Timer_Callback() {}
00903 };
00904 
00914 class Timer {
00915 protected:
00917         static Ticks ticks;
00918 
00920         struct ltuint { bool operator()(Ticks i1, Ticks i2) const {
00921                 return (i1 < i2);
00922         } };
00923 
00925         static std::multimap<Ticks,Timer_Callback*,ltuint> timers;
00926 
00927 public:
00929         static void check(Ticks ticks);
00930         static void check_to(Ticks ticks);
00931 
00933 
00934         static void add(Timer_Callback *cb, const Ticks ticks) { timers.insert(std::pair<const Ticks,Timer_Callback *>(ticks+Timer::ticks,cb)); }
00935 
00936         static void remove(const Timer_Callback *const cb);
00937 
00939         static Ticks now() { return ticks; }
00940 
00942         static Ticks next();
00943 };
00944 
00945 
00951 class ScreenRGB32le : public Screen {
00952 protected:
00954         virtual void rgbToSurface(RGB color, void **pixel) { RGB **p = (RGB **)pixel; **p = color; (*p)++; };
00955 
00957         virtual RGB surfaceToRGB(void *pixel) { return *(RGB*)pixel; };
00958 public:
00959         ScreenRGB32le(Size width, Size height) : Screen(width,height) {};
00960 
00961         virtual void paint(Drawable &d) const;
00962 };
00963 
00964 
00965 #ifdef SDL_MAJOR_VERSION
00966 
00980 class ScreenSDL : public Screen {
00981 protected:
00983         virtual void rgbToSurface(RGB color, void **pixel) { (void)color; (void)pixel; };
00984 
00986         virtual RGB surfaceToRGB(void *pixel) { (void)pixel; return 0; };
00987 
00989         SDL_Surface *surface;
00990         Uint32 start_abs_time,current_abs_time,current_time;
00991 
00993         int downx, downy;
00994 
00996         Ticks lastclick,lastdown;
00997 
00998 public:
00999 
01005         ScreenSDL(SDL_Surface *surface);
01006     virtual ~ScreenSDL();
01007 
01014         void setSurface(SDL_Surface *surface) { this->surface = surface; }
01015 
01017         SDL_Surface *getSurface() { return surface; }
01018 
01020         virtual void paint(Drawable &d) const;
01021 
01023         Ticks update(Ticks ticks);
01024 
01026         bool event(const SDL_Event *ev) { return event(*ev); }
01027 
01028         void watchTime();
01029         Uint32 getTime() { return current_time; }
01030 
01032         bool event(const SDL_Event& ev);
01033 };
01034 #endif
01035 
01036 class Font;
01037 
01056 class Drawable {
01057 protected:
01058         friend Ticks Screen::update(void *, Ticks);
01060         RGB *const buffer;
01062         const int width;
01064         const int height;
01066         const bool owner;
01067 
01069         RGB color;
01071         const Font *font;
01073         int lineWidth;
01074 
01076         const int tx;
01078         const int ty;
01080         const int cx;
01082         const int cy;
01084         const int cw;
01086         const int ch;
01088         const int fw;
01090         const int fh;
01091 
01093         int x;
01095         int y;
01096 
01097 public:
01099 
01100         Drawable(int w, int h, RGB clear = Color::Transparent);
01101 
01103 
01107         Drawable(Drawable &src, RGB clear = 0);
01108 
01110         Drawable(Drawable &src, int x, int y, int w, int h);
01111 
01113         virtual ~Drawable();
01114 
01116         void clear(RGB clear = Color::Transparent);
01117 
01119 
01123         void setColor(RGB c) { color = c; };
01125         RGB getColor() { return color; };
01126 
01128         void setFont(const Font *f) { font = f; };
01130         const Font *getFont() { return font; };
01131 
01133         void setLineWidth(int w) { lineWidth = w; };
01135         int getLineWidth() { return lineWidth; };
01136 
01138         void gotoXY(int x, int y) { this->x = x; this->y = y; };
01140         int getX() { return x; }
01142         int getY() { return y; }
01143 
01145         int getClipX() { return cx; }
01147         int getClipY() { return cy; }
01149         int getClipWidth() { return cw; }
01151         int getClipHeight() { return ch; }
01152 
01154         void drawPixel() { if (x >= cx && x < cw && y >= cy && y < ch) buffer[x+tx+(y+ty)*width] = color; };
01156         void drawPixel(int x, int y) { gotoXY(x,y); drawPixel(); };
01157 
01159         RGB getPixel() { if (x >= cx && x < cw && y >= cy && y < ch) return buffer[x+tx+(y+ty)*width]; return Color::Transparent; };
01161         RGB getPixel(int x, int y) { gotoXY(x,y); return getPixel(); };
01162 
01164         void drawLine(int x2, int y2);
01166         void drawLine(int x1, int y1, int x2, int y2) { gotoXY(x1,y1); drawLine(x2,y2); };
01167 
01169         void drawDotLine(int x2, int y2);
01171         void drawDotLine(int x1, int y1, int x2, int y2) { gotoXY(x1,y1); drawDotLine(x2,y2); };
01172 
01174 
01175         void drawCircle(int d);
01177 
01178         void drawCircle(int x, int y, int d) { gotoXY(x, y); drawCircle(d); };
01179 
01181 
01182         void drawRect(int w, int h);
01184 
01185         void drawRect(int x, int y, int w, int h) { gotoXY(x, y); drawRect(w, h); };
01186 
01188 
01189         void drawDotRect(int w, int h);
01191 
01192         void drawDotRect(int x, int y, int w, int h) { gotoXY(x, y); drawDotRect(w, h); };
01193 
01195 
01197         void fill();
01199 
01200         void fill(int x, int y) { gotoXY(x,y); fill(); };
01201 
01203 
01204         void fillCircle(int d);
01206 
01207         void fillCircle(int x, int y, int d) { gotoXY(x, y); fillCircle(d); };
01208 
01210 
01211         void fillRect(int w, int h);
01213 
01214         void fillRect(int x, int y, int w, int h) { gotoXY(x, y); fillRect(w, h); };
01215 
01217 
01223         void drawText(const String& text, bool interpret = true, Size start = 0, Size len = (Size)-1);
01224 
01226 
01227         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); }
01229 
01231         void drawText(const Char c, bool interpret = false);
01233 
01234         void drawText(int x, int y, const Char c, bool interpret = false) { gotoXY(x,y); drawText(c, interpret); }
01235 
01237 
01241         void drawDrawable(Drawable &d, unsigned char alpha = 1);
01243 
01245         void drawDrawable(int x, int y, Drawable &d, unsigned char alpha = 1) { gotoXY(x,y); drawDrawable(d, alpha); }
01246 
01247 };
01248 
01274 class Font {
01275 protected:
01276         friend void Drawable::drawText(const Char c, bool interpret);
01277         friend void Drawable::drawText(const String& s, bool interpret, Size start, Size len);
01278 
01280         struct ltstr { bool operator()(const char* s1, const char* s2) const {
01281                 return strcmp(s1, s2) < 0;
01282         } };
01284         static std::map<const char *,Font *,ltstr> registry;
01285 
01287         Font() {};
01288 
01290 
01292         virtual void drawChar(Drawable *d, const Char c) const = 0;
01293 
01295 
01296         virtual void drawString(Drawable *d, const String &s, Size start, Size len) const {
01297                 if (len > s.size()-start) len = (Size)(s.size()-start);
01298                 len += start;
01299                 while (start < len) drawChar(d,s[start++]);
01300         }
01301 
01302 public:
01304 
01305         static const Font *getFont(const char *name) {
01306                 std::map<const char *,Font *,ltstr>::iterator i = registry.find(name);
01307                 if (i == registry.end()) return(strcmp(name,"default")?getFont("default"):NULL);
01308                 return (*i).second;
01309         }
01310 
01311         static void registry_freeall() {
01312                 std::map<const char *,Font *,ltstr>::iterator it;
01313 
01314                 while ((it=registry.begin()) != registry.end()) {
01315                         delete it->second;
01316                         it->second = NULL;
01317                         registry.erase(it);
01318                 }
01319         }
01320 
01322 
01324         static void addFont(const char *name, Font *font) {
01325                 std::map<const char *,Font *,ltstr>::iterator i = registry.find(name);
01326                 if (i != registry.end()) delete (*i).second;
01327                 registry[name] = font;
01328         }
01329 
01330         virtual ~Font() {};
01331 
01333         virtual int getHeight() const = 0;
01334 
01336         virtual int getAscent() const = 0;
01337 
01339         template <typename STR> int getWidth(const STR s, Size start = 0, Size len = (Size)-1) const {
01340                 return this->getWidth(String(s), start, len);
01341         }
01342 
01344         virtual int getWidth(Char c = 'M') const = 0;
01345 
01347 
01348         virtual int getWidth(const String &s, Size start = 0, Size len = (Size)-1) const {
01349                 int width = 0;
01350                 if ((size_t)start+len > s.size()) len = (Size)(s.size()-start);
01351                 while (len--) width += getWidth(s[start++]);
01352                 return width;
01353         }
01354 
01356         enum SpecialChar { CR = '\r', LF = '\n', BS = '\b', Tab = '\t', Space = ' ', ESC = 27 };
01357 
01359         virtual SpecialChar toSpecial(Char c) const { return (SpecialChar)(c<255?c:255); }
01360 
01362         virtual Char fromSpecial(SpecialChar c) const { return c; }
01363 };
01364 
01371 class BitmapFont : public Font {
01372 protected:
01374         const unsigned char *const bitmap;
01375 
01377         const int width;
01378 
01380         const int height;
01381 
01383         const int ascent;
01384 
01386         const int *const widths;
01387 
01389 
01390         const int *const ascents;
01391 
01393         const bool background_set;
01394 
01396         const int col_step;
01397 
01399         const int row_step;
01400 
01402 
01403         const int character_step;
01404 
01406         const unsigned char *const*const char_position;
01407 
01409 
01410         const SpecialChar *const special;
01411 
01413         const bool owner;
01414 
01416         const Char last;
01417 
01419 
01421         virtual void drawChar(Drawable *d, const Char c) const;
01422 
01423 public:
01425 
01428         BitmapFont(const unsigned char *data, int height, int ascent, bool owner = false,
01429                 int width = 8, bool background_set = false,
01430                 int col_step = -1, int row_step = 8, int character_step = 0, Char last = 256,
01431                 const int *widths = NULL, const int *ascents = NULL,
01432                 const unsigned char *const* char_position = NULL,
01433                 const SpecialChar *special = NULL);
01434 
01435         virtual ~BitmapFont();
01436 
01438         virtual int getHeight() const { return height; };
01439 
01441         virtual int getAscent() const { return ascent; };
01442 
01444         virtual int getWidth(Char c = 'M') const { return (widths != NULL?widths[c]:width); };
01445 
01447         virtual SpecialChar toSpecial(Char c) const { return (special != NULL?special[c]:Font::toSpecial(c)); }
01448 
01450         virtual Char fromSpecial(SpecialChar c) const { if (special == NULL) return Font::fromSpecial(c); Char i = 0; while(special[i] != c) i++; return i; }
01451 
01452 };
01453 
01454 class ActionEventSource;
01456 struct ActionEventSource_Callback {
01457 public:
01459 
01460                 virtual void actionExecuted(ActionEventSource *source, const String &arg) = 0;
01461                 virtual ~ActionEventSource_Callback() {}
01462 };
01463 
01465 
01470 class ActionEventSource {
01471 protected:
01473         std::list<ActionEventSource_Callback *> actionHandlers;
01474 
01476 
01478         String name;
01479 
01480 public:
01482         template <typename STR> ActionEventSource(const STR name) : name(String(name)) { }
01483 
01485         virtual ~ActionEventSource() {}
01486 
01488         void addActionHandler(ActionEventSource_Callback *handler) { actionHandlers.push_back(handler); }
01489 
01491         void removeActionHandler(ActionEventSource_Callback *handler) { actionHandlers.remove(handler); }
01492 
01494         template <typename STR> void setName(const STR name) { this->name = String(name); }
01495 
01497         const String &getName() const { return name; }
01498 
01500         void executeAction(const String &arg) {
01501                 std::list<ActionEventSource_Callback*>::iterator i = actionHandlers.begin();
01502                 bool end = (i == actionHandlers.end());
01503                 while (!end) {
01504                         ActionEventSource_Callback *c = *i;
01505                         ++i;
01506                         end = (i == actionHandlers.end());
01507                         c->actionExecuted(this,arg);
01508                 }
01509         }
01510 
01512         void executeAction() { executeAction(name); }
01513 };
01514 
01516 class BorderedWindow : public Window {
01517 protected:
01519         int border_left, border_top, border_right, border_bottom;
01520 
01522         BorderedWindow(Window *parent, int x, int y, int w, int h, int bl, int bt, int br, int bb) :
01523                 Window(parent,x,y,w,h), border_left(bl), border_top(bt), border_right(br), border_bottom(bb) {}
01524 
01525 public:
01526         virtual void paintAll(Drawable &d) const;
01527         virtual bool mouseMoved(int x, int y);
01528         virtual bool mouseDown(int x, int y, MouseButton button);
01529         virtual bool mouseDragged(int x, int y, MouseButton button);
01530         virtual bool mouseUp(int x, int y, MouseButton button);
01531         virtual int getScreenX() const { return Window::getScreenX()+border_left; }
01532         virtual int getScreenY() const { return Window::getScreenY()+border_top; }
01533 };
01534 
01536 
01540 class Label : public Window {
01542         const Font *font;
01543 
01545         RGB color;
01546 
01548         String text;
01549 
01551         bool interpret;
01552 
01553 public:
01554 
01555     bool allow_focus = false;
01556 
01558 
01559         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) :
01560                 Window(parent, x, y, (width?width:1), 1), font(font), color(color), text(text), interpret(width != 0)
01561         { resize(); tabbable = false; }
01562 
01564         template <typename STR> void setText(const STR text) { this->text = text; resize(); }
01566         const String& getText() { return text; }
01567 
01569         void setFont(const Font *font) { this->font = font; resize(); }
01571         const Font *getFont() { return font; }
01572 
01574         void setColor(const RGB color) { this->color = color; resize(); }
01576         RGB getColor() { return color; }
01577 
01579         virtual void resize(int w = -1, int h = -1) {
01580         (void)h;//UNUSED
01581                 if (w == -1) w = (interpret?getWidth():0);
01582                 else interpret = (w != 0);
01583                 Drawable d((w?w:1), 1);
01584                 d.setFont(font);
01585                 d.drawText(0, font->getAscent(), text, interpret, 0);
01586                 if (interpret) Window::resize(w, d.getY()-font->getAscent()+font->getHeight());
01587                 else Window::resize(d.getX(), font->getHeight());
01588         }
01589 
01591         virtual bool hasFocus() const { return allow_focus && Window::hasFocus(); }
01592 
01594         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); }
01595 
01596         virtual bool raise() { return false; }
01597 };
01598 
01599 
01601 
01604 class Input : public Window, public Timer_Callback, public ActionEventSource {
01605 protected:
01607         String text;
01608 
01610         Size pos;
01611 
01613         Size lastpos;
01614 
01616         int posx, posy;
01617 
01619         Size start_sel, end_sel;
01620 
01622         bool blink;
01623 
01625         bool insert;
01626 
01628         bool multi;
01629 
01631         int offset;
01632 
01634     bool enable_tab_input;
01635 
01637         void checkOffset() {
01638                 if (lastpos == pos) return;
01639                 const Font *f = Font::getFont("input");
01640                 if (multi) {
01641                         Drawable d(width-6,1);
01642                         d.setFont(f);
01643                         d.drawText(0, 0, text, multi, 0, pos);
01644                         posy = d.getY();
01645                         posx = d.getX();
01646                         if (posy-offset > height-8-f->getHeight()) offset = posy-height+8+f->getHeight();
01647                         if (posy-offset < 0) offset = posy;
01648                 } else {
01649                         posy = 0;
01650                         posx = f->getWidth(text,0,pos);
01651                         if (f->getWidth(text,0,pos+1)-offset > width-10) offset = f->getWidth(text,0,pos+1)-width+10;
01652                         if (f->getWidth(text,0,(pos>0?pos-1:0))-offset < 0) offset = f->getWidth(text,0,(pos>0?pos-1:0));
01653                 }
01654                 lastpos = pos;
01655                 setDirty();
01656         }
01657 
01658 public:
01660         Input(Window *parent, int x, int y, int w, int h = 0) :
01661                 Window(parent,x,y,w,(h?h:Font::getFont("input")->getHeight()+10)), ActionEventSource("GUI::Input"),
01662                 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)
01663         { Timer::add(this,30); }
01664 
01665         ~Input() {
01666                 Timer::remove(this);
01667         }
01668 
01670         virtual void paint(Drawable &d) const;
01671 
01673         void clearSelection() {
01674                 text.erase(text.begin()+int(pos = imin(start_sel,end_sel)),text.begin()+int(imax(start_sel,end_sel)));
01675                 start_sel = end_sel = pos;
01676         }
01677 
01679         void copySelection() {
01680                 setClipboard(String(text.begin()+int(imin(start_sel,end_sel)),text.begin()+int(imax(start_sel,end_sel))));
01681         }
01682 
01684         void cutSelection() {
01685                 setClipboard(String(text.begin()+int(imin(start_sel,end_sel)),text.begin()+int(imax(start_sel,end_sel))));
01686                 clearSelection();
01687         }
01688 
01690         void pasteSelection() {
01691                 String c = getClipboard();
01692                 clearSelection();
01693                 text.insert(text.begin()+int(pos),c.begin(),c.end());
01694                 start_sel = end_sel = pos += (Size)c.size();
01695         }
01696 
01698         Size findPos(int x, int y);
01699 
01701         template <typename STR> void setText(const STR text) { this->text = text; setDirty(); }
01703         const String& getText() { return text; };
01704 
01706         virtual bool keyDown(const Key &key);
01707 
01709         virtual bool mouseDown(int x, int y, MouseButton button);
01710 
01712         virtual bool mouseDragged(int x, int y, MouseButton button);
01713 
01715         virtual Ticks timerExpired(Ticks time)
01716         { (void)time; blink = !blink; setDirty(); return 30; }
01717 
01719         virtual void posToEnd(void);
01720 };
01721 
01722 class ToplevelWindow;
01724 struct ToplevelWindow_Callback {
01725 public:
01727 
01730                 virtual bool windowClosing(ToplevelWindow *win) = 0;
01731 
01733 
01737                 virtual void windowClosed(ToplevelWindow *win) = 0;
01738                 virtual ~ToplevelWindow_Callback() {}
01739 };
01740 
01742 class ToplevelWindow : public BorderedWindow, public ActionEventSource_Callback {
01743 protected:
01745         String title;
01746 
01748         int dragx, dragy;
01749 
01751         std::list<ToplevelWindow_Callback *> closehandlers;
01752 
01754         Menu *systemMenu;
01755 
01756 public:
01758         template <typename STR> ToplevelWindow(Screen *parent, int x, int y, int w, int h, const STR title);
01759 
01761         ~ToplevelWindow() {
01762                 std::list<ToplevelWindow_Callback*>::iterator i = closehandlers.begin();
01763                 bool end = (i == closehandlers.end());
01764                 while (!end) {
01765                         ToplevelWindow_Callback *c = *i;
01766                         ++i;
01767                         end = (i == closehandlers.end());
01768                         c->windowClosed(this);
01769                 }
01770         }
01771 
01773         virtual void actionExecuted(ActionEventSource *src, const String &item) {
01774         (void)src;
01775                 if (item == String("Close")) close();
01776         }
01777 
01779         void addCloseHandler(ToplevelWindow_Callback *handler) { closehandlers.push_back(handler); }
01780 
01782         void removeCloseHandler(ToplevelWindow_Callback *handler) { closehandlers.remove(handler); }
01783 
01784         virtual void paint(Drawable &d) const;
01785         virtual bool mouseDown(int x, int y, MouseButton button);
01786         virtual bool mouseDoubleClicked(int x, int y, MouseButton button);
01787         virtual bool mouseUp(int x, int y, MouseButton button) {
01788                 if (button == Left && dragx >= 0 && dragy >= 0) {
01789                         dragx = dragy = -1;
01790                         return true;
01791                 }
01792                 BorderedWindow::mouseUp(x,y,button);
01793                 return true;
01794         }
01795         virtual bool mouseDragged(int x, int y, MouseButton button) {
01796                 if (button == Left && dragx >= 0 && dragy >= 0) {
01797                         move(x-dragx+this->x,y-dragy+this->y);
01798                         return true;
01799                 }
01800                 BorderedWindow::mouseDragged(x,y,button);
01801                 return true;
01802         }
01803         virtual bool mouseMoved(int x, int y) {
01804                 BorderedWindow::mouseMoved(x,y);
01805                 return true;
01806         }
01807 
01809         virtual bool raise() {
01810                 Window *last = parent->children.back();
01811                 parent->children.remove(this);
01812                 parent->children.push_back(this);
01813                 if (last != this) {
01814                         focusChanged(true);
01815                         last->focusChanged(false);
01816                 }
01817                 return true;
01818         }
01819 
01821         template <typename STR> void setTitle(const STR title) { this->title = title; setDirty(); }
01823         const String& getTitle() { return title; }
01824 
01826         void close() {
01827                 bool doit = true;
01828                 std::list<ToplevelWindow_Callback*>::iterator i = closehandlers.begin();
01829                 bool end = (i == closehandlers.end());
01830                 while (!end) {
01831                         ToplevelWindow_Callback *c = *i;
01832                         ++i;
01833                         end = (i == closehandlers.end());
01834                         doit = doit && c->windowClosing(this);
01835                 }
01836                 if (doit) delete this;
01837         }
01838 };
01839 
01841 
01855 class TransientWindow : public Window, Window_Callback, ToplevelWindow_Callback {
01856 protected:
01858         Window *realparent;
01859 
01861         int relx, rely;
01862 
01863 public:
01865         virtual void focusChanged(bool gained) {
01866                 Window::focusChanged(gained);
01867                 if (isVisible() && !gained) {
01868                         if (realparent->hasFocus()) raise();
01869                         else setVisible(false);
01870                 }
01871         }
01872 
01874         void windowClosed(ToplevelWindow *win) {
01875         (void)win;
01876                 delete this;
01877         }
01878 
01880         bool windowClosing(ToplevelWindow *win) { (void)win; return true; }
01881 
01883 
01885         TransientWindow(Window *parent, int x, int y, int w, int h) :
01886                 Window(parent->getScreen(),x+parent->getScreenX(),y+parent->getScreenY(),w,h),
01887                 realparent(parent), relx(x), rely(y) {
01888                 Window *p = realparent, *last = NULL, *last2 = NULL;
01889                 while (p != NULL) {
01890                         p->addWindowHandler(this);
01891                         last2 = last;
01892                         last = p;
01893                         p = p->getParent();
01894                 }
01895         transient = true;
01896                 dynamic_cast<ToplevelWindow *>(last2)->addCloseHandler(this);
01897         }
01898 
01899         ~TransientWindow() {
01900                 Window *p = realparent, *last = NULL, *last2 = NULL;
01901                 while (p != NULL) {
01902                         p->removeWindowHandler(this);
01903                         last2 = last;
01904                         last = p;
01905                         p = p->getParent();
01906                 }
01907                 dynamic_cast<ToplevelWindow *>(last2)->removeCloseHandler(this);
01908          }
01909 
01910         virtual void move(int x, int y) { relx = x; rely = y;
01911                 Window::move(x+realparent->getScreenX(),y+realparent->getScreenY()); }
01912         virtual int getX() const { return x-realparent->getScreenX(); }
01913         virtual int getY() const { return y-realparent->getScreenY(); }
01914         virtual void setVisible(bool v) { if (v) raise(); Window::setVisible(v); }
01915         virtual void windowMoved(Window *src, int x, int y) { (void)src; (void)x; (void)y; move(relx,rely); }
01916     virtual bool mouseDownOutside(MouseButton button) {
01917         (void)button;
01918 
01919         if (visible) {
01920             setVisible(false);
01921             return true;
01922         }
01923 
01924         return false;
01925     }
01926 
01928         virtual bool raise() {
01929                 Window *last = parent->children.back();
01930                 parent->children.remove(this);
01931                 parent->children.push_back(this);
01932                 if (last != this) {
01933                         focusChanged(true);
01934                         last->focusChanged(false);
01935                 }
01936                 return true;
01937         }
01938 
01939 };
01940 
01942 
01951 class Menu : public TransientWindow, public ActionEventSource {
01952 protected:
01954         std::vector<String> items;
01955 
01957 
01958         int selected;
01959 
01961         bool firstMouseUp;
01962 
01964         Window *mouseTakenFrom;
01965 
01967 
01968         virtual void selectItem(int x, int y) {
01969         (void)x;//UNUSED
01970                 y -= 2;
01971                 selected = -1;
01972 
01973         // mouse input should select nothing if outside the bounds of this menu
01974         if (x < 0 || x >= width || y < 0 || y >= height) return;
01975 
01976                 const int height = Font::getFont("menu")->getHeight()+2;
01977                 std::vector<String>::iterator i;
01978                 for (i = items.begin(); i != items.end() && y > 0; ++i) {
01979                         selected++;
01980                         if ((*i).size() > 0) y -= height;
01981                         else y -= 12;
01982                 }
01983                 if (y > 0 || (selected >= 0 && items[(unsigned int)selected].size() == 0)) selected = -1;
01984         }
01985 
01986         virtual Size getPreferredWidth() {
01987                 Size width = 0;
01988                 const Font *f = Font::getFont("menu");
01989                 std::vector<String>::iterator i;
01990                 for (i = items.begin(); i != items.end() && y > 0; ++i) {
01991                         Size newwidth = (unsigned int)f->getWidth(*i);
01992                         if (newwidth > width) width = newwidth;
01993                 }
01994                 return width+39;
01995         }
01996 
01997         virtual Size getPreferredHeight() {
01998                 Size height = 0;
01999                 const Size h = (unsigned int)Font::getFont("menu")->getHeight()+2u;
02000                 std::vector<String>::iterator i;
02001                 for (i = items.begin(); i != items.end() && y > 0; ++i) {
02002                         height += ((*i).size() > 0?h:12);
02003                 }
02004                 return height+6;
02005         }
02006 
02007 public:
02009 
02011         template <typename STR> Menu(Window *parent, int x, int y, const STR name) :
02012                 TransientWindow(parent,x,y,4,4), ActionEventSource(name), selected(-1)
02013                 { setVisible(false); tabbable = false; }
02014 
02015         ~Menu() {
02016                 setVisible(false);
02017         }
02018 
02020         virtual void paint(Drawable &d) const;
02021 
02023         virtual bool mouseMoved(int x, int y)  {
02024         if (visible) {
02025             firstMouseUp = false;
02026                 selectItem(x,y);
02027                 return true;
02028         }
02029 
02030         return false;
02031         }
02032 
02033     void mouseMovedOutside(void) {
02034         if (visible && selected >= 0) {
02035             firstMouseUp = false;
02036             selected = -1;
02037             setDirty();
02038         }
02039     }
02040 
02042         virtual bool mouseDragged(int x, int y, MouseButton button)  {
02043         (void)button;//UNUSED   
02044 
02045         if (visible) {
02046             if (x >= 0 && x < width && y >= 0 && y < height)
02047                 firstMouseUp = false;
02048 
02049             selectItem(x,y);
02050             return true;
02051         }
02052 
02053         return false;
02054         }
02055 
02056         virtual bool mouseDown(int x, int y, MouseButton button)  {
02057         (void)button;//UNUSED
02058         (void)x;//UNUSED
02059         (void)y;//UNUSED
02060 
02061         if (visible)
02062             return true;
02063 
02064         return false;
02065     }
02066 
02067         virtual bool mouseDownOutside(MouseButton button) {
02068         (void)button;//UNUSED
02069 
02070         if (visible) {
02071             setVisible(false);
02072             selected = -1;
02073             return true;
02074         }
02075 
02076         return false;
02077     }
02078 
02080         virtual bool mouseUp(int x, int y, MouseButton button)  {
02081         (void)button;//UNUSED
02082 
02083         if (visible) {
02084             selectItem(x,y);
02085             if (firstMouseUp) firstMouseUp = false;
02086             else setVisible(false);
02087             execute();
02088             return true;
02089         }
02090 
02091         return false;
02092     }
02093 
02095         virtual bool keyDown(const Key &key) {
02096         if (visible) {
02097             if (key.special == Key::Up) {
02098                 if (selected == 0)
02099                     selected = (int)items.size() - 1;
02100                 else
02101                     selected--;
02102             }
02103             else if (key.special == Key::Down) {
02104                 if ((size_t)(++selected) == items.size())
02105                     selected = 0;
02106             }
02107             else if (key.special == Key::Enter) { execute(); return true; }
02108             else if (key.special == Key::Escape) { setVisible(false); selected = -1; return true; }
02109             else return true;
02110             if (items[(unsigned int)selected].size() == 0 && items.size() > 1) return keyDown(key);
02111             if (selected < 0) selected = (int)(items.size()-1);
02112             if (selected >= (int)items.size()) selected = 0;
02113             return true;
02114         }
02115 
02116         return false;
02117         }
02118 
02119 
02121         template <typename T> void addItem(const T item) {
02122                 items.push_back(String(item));
02123                 resize((int)getPreferredWidth(),(int)getPreferredHeight());
02124         }
02125 
02127         template <typename T> void removeItem(const T item) {
02128                 const String s(item);
02129                 std::vector<String>::iterator i = items.begin();
02130                 while (i != items.end() && s != (*i)) ++i;
02131                 if (i != items.end()) items.erase(i);
02132                 resize(getPreferredWidth(),getPreferredHeight());
02133         }
02134 
02135         virtual void setVisible(bool v) {
02136         if (!visible && v)
02137             firstMouseUp = true;
02138 
02139         TransientWindow::setVisible(v);
02140                 if (v) {
02141                         parent->mouseChild = this;
02142                         raise();
02143                 }
02144 
02145         // NTS: Do not set selected = -1 here on hide, other code in this C++
02146         //      class relies on calling setVisible() then acting on selection.
02147         //      Unless of course you want to hunt down random and sporadic
02148         //      segfaults. --J.C.
02149         }
02150 
02152         void execute() {
02153                 if (selected >= 0) {
02154                         setVisible(false);
02155 
02156             // FIXME: Some action callbacks including the "Close" command in
02157             //        the system menu will delete this window object before
02158             //        returning to this level in the call stack. Therefore,
02159             //        copy selection index and clear it BEFORE calling the
02160             //        callbacks.
02161             unsigned int sel = (unsigned int)selected;
02162             selected = -1;
02163 
02164                         executeAction(items[sel]);
02165 
02166             // WARNING: Do not access C++ class methods or variables here,
02167             //          the "Close" callback may have deleted this window
02168             //          out from under us! It may happen to work but
02169             //          understand it becomes a use-after-free bug!
02170                 }
02171         }
02172 };
02173 
02175 
02178 class Button : public BorderedWindow, public ActionEventSource {
02179 protected:
02181         bool pressed;
02182 
02183 public:
02185         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) {}
02186 
02188 
02189         template <typename T> Button(Window *parent, int x, int y, const T text, int w = -1, int h = -1);
02190 
02192         virtual void paint(Drawable &d) const;
02193 
02195         virtual bool mouseDown(int x, int y, MouseButton button) {
02196         (void)button;//UNUSED
02197         (void)x;//UNUSED
02198         (void)y;//UNUSED
02199         
02200                 if (button == Left) {
02201                         border_left = 7; border_right = 5; border_top = 7; border_bottom = 3;
02202                         pressed = true;
02203                 }
02204                 return true;
02205         }
02206 
02208         virtual bool mouseUp(int x, int y, MouseButton button)  {
02209         (void)button;//UNUSED
02210         (void)x;//UNUSED
02211         (void)y;//UNUSED
02212         
02213                 if (button == Left) {
02214                         border_left = 6; border_right = 6; border_top = 5; border_bottom = 5;
02215                         pressed = false;
02216                 }
02217                 return true;
02218         }
02219 
02221         virtual bool mouseClicked(int x, int y, MouseButton button) {
02222         (void)button;//UNUSED
02223         (void)x;//UNUSED
02224         (void)y;//UNUSED
02225         
02226                 if (button == Left) {
02227                         executeAction();
02228                         return true;
02229                 }
02230                 return false;
02231         }
02232 
02234         virtual bool keyDown(const Key &key);
02235 
02237         virtual bool keyUp(const Key &key);
02238 
02239 };
02240 
02242 
02248 class Menubar : public Window, public ActionEventSource, ActionEventSource_Callback {
02249 protected:
02251         int selected;
02252 
02254         int lastx;
02255 
02257         std::vector<Menu*> menus;
02258 
02259 public:
02261 
02262         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; }
02263 
02265         template <typename STR> void addMenu(const STR name) {
02266                 const String n(name);
02267                 menus.push_back(new Menu(this,lastx,height-2,n));
02268                 menus.back()->addActionHandler(this);
02269                 lastx += Font::getFont("menu")->getWidth(n)+14;
02270         }
02271 
02273         template <typename STR> void addItem(int index, const STR name) { menus[(unsigned int)index]->addItem(name); }
02274 
02276         template <typename STR> void removeItem(int index, const STR name) { menus[(unsigned int)index]->removeItem(name); }
02277 
02279         virtual void paint(Drawable &d) const;
02280 
02282         virtual bool mouseDown(int x, int y, MouseButton button) {
02283         (void)button;//UNUSED
02284         (void)y;//UNUSED
02285                 int oldselected = selected;
02286                 if (selected >= 0 && !menus[(unsigned int)selected]->isVisible()) oldselected = -1;
02287                 if (selected >= 0) menus[(unsigned int)selected]->setVisible(false);
02288                 if (x < 0 || x >= lastx) return true;
02289                 for (selected = (int)(menus.size()-1); menus[(unsigned int)selected]->getX() > x; selected--) {};
02290                 if (oldselected == selected) selected = -1;
02291                 else menus[(unsigned int)selected]->setVisible(true);
02292                 return true;
02293         }
02294 
02296         virtual bool keyDown(const Key &key) {
02297         if (key.special == Key::Tab)
02298             return false;
02299 
02300         return true;
02301     }
02302 
02304     virtual bool keyUp(const Key &key) {
02305         if (key.special == Key::Tab)
02306             return false;
02307 
02308         return true;
02309     }
02310 
02311         virtual void actionExecuted(ActionEventSource *src, const String &arg) {
02312                 std::list<ActionEventSource_Callback*>::iterator i = actionHandlers.begin();
02313                 bool end = (i == actionHandlers.end());
02314                 while (!end) {
02315                         ActionEventSource_Callback *c = *i;
02316                         ++i;
02317                         end = (i == actionHandlers.end());
02318                         c->actionExecuted(src,arg);
02319                 }
02320         }
02321 };
02322 
02324 
02327 class Checkbox : public BorderedWindow, public ActionEventSource {
02328 protected:
02330         bool checked;
02331 
02332 public:
02334         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) {}
02335 
02337 
02338         template <typename T> Checkbox(Window *parent, int x, int y, const T text, int w = -1, int h = -1);
02339 
02341         virtual void paint(Drawable &d) const;
02342 
02344         virtual void setChecked(bool checked) { this->checked = checked; }
02345 
02347         virtual bool isChecked() { return checked; }
02348 
02350         virtual bool mouseDown(int x, int y, MouseButton button) {
02351         (void)button;//UNUSED
02352         (void)x;//UNUSED
02353         (void)y;//UNUSED        
02354                 checked = !checked;
02355                 return true;
02356         }
02357 
02359         virtual bool mouseUp(int x, int y, MouseButton button)  {
02360         (void)button;//UNUSED
02361         (void)x;//UNUSED
02362         (void)y;//UNUSED        
02363                 execute();
02364                 return true;
02365         }
02366 
02368         virtual bool keyDown(const Key &key);
02369 
02371         virtual bool keyUp(const Key &key);
02372 
02374         virtual void execute() {
02375                 String arg(name);
02376                 if (!checked) arg.insert(arg.begin(),'!');
02377                 executeAction(arg);
02378         }
02379 };
02380 
02381 class Frame;
02382 
02384 
02387 class Radiobox : public BorderedWindow, public ActionEventSource {
02388 protected:
02390         bool checked;
02391 
02392 public:
02394         Radiobox(Frame *parent, int x, int y, int w, int h);
02395 
02397 
02398         template <typename T> Radiobox(Frame *parent, int x, int y, const T text, int w = -1, int h = -1);
02399 
02401         virtual void paint(Drawable &d) const;
02402 
02404         virtual void setChecked(bool checked) { this->checked = checked; }
02405 
02407         virtual bool isChecked() { return checked; }
02408 
02410         virtual bool mouseDown(int x, int y, MouseButton button) {
02411         (void)button;//UNUSED
02412         (void)x;//UNUSED
02413         (void)y;//UNUSED
02414         checked = true;
02415                 return true;
02416         }
02417 
02419         virtual bool mouseUp(int x, int y, MouseButton button)  {
02420         (void)button;//UNUSED
02421         (void)x;//UNUSED
02422         (void)y;//UNUSED
02423                 executeAction();
02424                 return true;
02425         }
02426 
02428         virtual bool keyDown(const Key &key);
02429 
02431         virtual bool keyUp(const Key &key);
02432 };
02433 
02435 
02437 class Frame : public BorderedWindow, public ActionEventSource, protected ActionEventSource_Callback {
02438 protected:
02439         friend class Radiobox;
02440 
02442         int selected;
02443 
02445         String label;
02446 
02448         virtual void actionExecuted(ActionEventSource *src, const String &arg) {
02449         // HACK: Attempting to cast a String to void causes "forming reference to void" errors when building with GCC 4.7
02450         (void)arg.size();//UNUSED
02451                 for (std::list<Window *>::iterator i = children.begin(); i != children.end(); ++i) {
02452                         Radiobox *r = dynamic_cast<Radiobox*>(*i);
02453                         if (r != NULL && src != dynamic_cast<ActionEventSource*>(r)) r->setChecked(false);
02454                 }
02455                 executeAction(src->getName());
02456         }
02457 
02458 public:
02460         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) {}
02461 
02463         template <typename T> Frame(Window *parent, int x, int y, int w, int h, const T text) :
02464                 BorderedWindow(parent,x,y,w,h,5,Font::getFont("default")->getHeight()+2,5,5),
02465                 ActionEventSource(text), selected(0), label(text) { }
02466 
02468         virtual void paint(Drawable &d) const;
02469 
02470 };
02471 
02473 class MessageBox2 : public GUI::ToplevelWindow {
02474 protected:
02475         Label *message;
02476         Button *close;
02477     WindowInWindow *wiw;
02478 public:
02480         template <typename STR> MessageBox2(Screen *parent, int x, int y, int width, const STR title, const STR text) :
02481                 ToplevelWindow(parent, x, y, width, 1, title) {
02482         wiw = new WindowInWindow(this, 5, 5, width-border_left-border_right-10, 70);
02483                 message = new Label(wiw, 0, 0, text, width-border_left-border_right-10);
02484                 close = new GUI::Button(this, (width-border_left-border_right-70)/2, 10, "Close", 70);
02485                 close->addActionHandler(this);
02486                 setText(text);
02487 
02488                 close->raise(); /* make sure keyboard focus is on the close button */
02489                 this->raise(); /* make sure THIS WINDOW has the keyboard focus */
02490         }
02491 
02493         template <typename STR> void setText(const STR text) {
02494         int sfh;
02495         int msgw;
02496         bool scroll = true;
02497 
02498         msgw = width-border_left-border_right-10;
02499         message->resize(msgw, message->getHeight());
02500                 message->setText(text);
02501 
02502         {
02503             Screen *s = getScreen();
02504             sfh = s->getHeight() - 70 - border_top - border_bottom;
02505             if (sfh > (15+message->getHeight())) {
02506                 sfh = (15+message->getHeight());
02507                 scroll = false;
02508             }
02509         }
02510 
02511         wiw->enableBorder(scroll);
02512         wiw->enableScrollBars(false/*h*/,scroll/*v*/);
02513         if (scroll) {
02514             msgw -= wiw->vscroll_display_width;
02515             msgw -= 2/*border*/;
02516             message->resize(msgw, message->getHeight());
02517         }
02518 
02519                 close->move((width-border_left-border_right-70)/2, sfh);
02520         wiw->resize(width-border_left-border_right-10, sfh-10);
02521                 resize(width, sfh+close->getHeight()+border_bottom+border_top+5);
02522         }
02523 
02524         virtual bool keyDown(const GUI::Key &key) {
02525         if (GUI::ToplevelWindow::keyDown(key)) return true;
02526         return false;
02527     }
02528 
02529         virtual bool keyUp(const GUI::Key &key) {
02530         if (GUI::ToplevelWindow::keyUp(key)) return true;
02531 
02532         if (key.special == GUI::Key::Escape) {
02533             close->executeAction();
02534             return true;
02535         }
02536 
02537         return false;
02538     }
02539 };
02540 
02541 extern int titlebar_y_start;
02542 extern int titlebar_y_stop;
02543 
02544 extern int titlebox_y_start;
02545 extern int titlebox_y_height;
02546 
02547 template <typename STR> ToplevelWindow::ToplevelWindow(Screen *parent, int x, int y, int w, int h, const STR title) :
02548         BorderedWindow(parent, x, y, w, h, 6, titlebar_y_stop, 6, 3), title(title),
02549         dragx(-1), dragy(-1), closehandlers(), systemMenu(new Menu(this,-1,-2,"System Menu")) {
02550 /* If these commands don't do anything, then why have them there?? --J.C. */
02551 #if 0 /* TODO: Allow selective enabling these if the Window object wants us to */
02552         systemMenu->addItem("Move");
02553         systemMenu->addItem("Resize");
02554         systemMenu->addItem("");
02555         systemMenu->addItem("Minimize");
02556         systemMenu->addItem("Maximize");
02557         systemMenu->addItem("Restore");
02558         systemMenu->addItem("");
02559 #endif
02560         systemMenu->addItem("Close");
02561         systemMenu->addActionHandler(this);
02562     toplevel = true;
02563 }
02564 
02565 template <typename STR> Button::Button(Window *parent, int x, int y, const STR text, int w, int h) :
02566         BorderedWindow(parent,x,y,w,h,6,5,6,5), ActionEventSource(text), pressed(0)
02567 {
02568 
02569         Label *l = new Label(this,0,0,text);
02570     l->allow_focus = true;
02571         if (width < 0) resize(l->getWidth()+border_left+border_right+10,height);
02572         if (height < 0) resize(width,l->getHeight()+border_top+border_bottom+6);
02573         l->move((width-border_left-border_right-l->getWidth())/2,
02574                 (height-border_top-border_bottom-l->getHeight())/2);
02575 }
02576 
02577 template <typename STR> Checkbox::Checkbox(Window *parent, int x, int y, const STR text, int w, int h) :
02578         BorderedWindow(parent,x,y,w,h,16,0,0,0), ActionEventSource(text), checked(0)
02579 {
02580         Label *l = new Label(this,0,0,text);
02581         if (width < 0) resize(l->getWidth()+border_left+border_right+4,height);
02582         if (height < 0) resize(width,l->getHeight()+border_top+border_bottom+4);
02583         l->move((width-border_left-border_right-l->getWidth())/2,
02584                 (height-border_top-border_bottom-l->getHeight())/2);
02585 }
02586 
02587 template <typename STR> Radiobox::Radiobox(Frame *parent, int x, int y, const STR text, int w, int h) :
02588         BorderedWindow(parent,x,y,w,h,16,0,0,0), ActionEventSource(text), checked(0)
02589 {
02590         Label *l = new Label(this,0,0,text);
02591         if (width < 0) resize(l->getWidth()+border_left+border_right+4,height);
02592         if (height < 0) resize(width,l->getHeight()+border_top+border_bottom+4);
02593         l->move((width-border_left-border_right-l->getWidth())/2,
02594                 (height-border_top-border_bottom-l->getHeight())/2);
02595         addActionHandler(parent);
02596 }
02597 
02598 }
02599 
02600 #endif