DOSBox-X
|
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