DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/libs/gui_tk/gui_tk.cpp
Go to the documentation of this file.
00001 /*
00002  *  gui_tk - framework-agnostic GUI toolkit
00003  *  Copyright (C) 2005-2013 Jörg Walter
00004  *
00005  *  gui_tk is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 3 of the License, or
00008  *  (at your option) any later version.
00009  *
00010  *  gui_tk is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program.  If not, see <http://www.gnu.org/licenses/>
00017  */
00018 
00019 /* TODO:
00020   - make menu a bufferedwindow with shadow
00021 */
00022 
00032 #include "config.h"
00033 
00034 #if !defined(C_SDL2)
00035 #include <SDL.h>
00036 #include "gui_tk.h"
00037 
00038 namespace GUI {
00039 
00040 namespace Color {
00041         RGB Background3D =              0xffc0c0c0;
00042         RGB Light3D =                   0xfffcfcfc;
00043         RGB Shadow3D =                  0xff808080;
00044         RGB Border =                    0xff000000;
00045         RGB Text =                      0xff000000;
00046         RGB Background =                0xffc0c0c0;
00047         RGB SelectionBackground =       0xff000080;
00048         RGB SelectionForeground =       0xffffffff;
00049         RGB EditableBackground =        0xffffffff;
00050         RGB Titlebar =                  0xff000080;
00051         RGB TitlebarText =              0xffffffff;
00052 }
00053 
00054 std::map<const char *,Font *,Font::ltstr> Font::registry;
00055 
00056 bool ToplevelWindow::mouseDoubleClicked(int x, int y, MouseButton button) {
00057         if (button == Left && x < 32 && x > 6 && y > 4 && y < 31) {
00058                 systemMenu->executeAction("Close");
00059                 return true;
00060         }
00061         BorderedWindow::mouseClicked(x,y,button);
00062         return true;
00063 }
00064 
00065 void Drawable::drawText(const String& text, bool interpret, Size start, Size len) {
00066         if (interpret) {
00067                 if (len > text.size()-start) len = (Size)(text.size()-start);
00068                 len += start;
00069 
00070                 Size wordstart = start;
00071                 int width = 0;
00072 
00073                 while (start < len) {
00074                         switch (font->toSpecial(text[start])) {
00075                         case Font::CR:
00076                                 if (wordstart != start) {
00077                                         drawText(text,false,wordstart,start-wordstart);
00078                                         wordstart = start;
00079                                         width = 0;
00080                                 }
00081                                 wordstart++;
00082                                 gotoXY(0,y);
00083                                 break;
00084                         case Font::LF:
00085                                 if (wordstart != start) {
00086                                         drawText(text,false,wordstart,start-wordstart);
00087                                         wordstart = start;
00088                                         width = 0;
00089                                 }
00090                                 wordstart++;
00091                                 gotoXY(0,y+font->getHeight());
00092                                 break;
00093                         case Font::BS:
00094                                 if (wordstart != start) {
00095                                         drawText(text,false,wordstart,start-wordstart);
00096                                         wordstart = start;
00097                                         width = 0;
00098                                 }
00099                                 wordstart++;
00100                                 gotoXY(imax(0,x-font->getWidth()),y);
00101                                 break;
00102                         case Font::Tab:
00103                                 if (wordstart != start) {
00104                                         drawText(text,false,wordstart,start-wordstart);
00105                                         wordstart = start;
00106                                         width = 0;
00107                                 }
00108                                 wordstart++;
00109                                 gotoXY((((int)(x/font->getWidth()/8))+1)*8*font->getWidth(),y);
00110                                 break;
00111                         case Font::Space:
00112                                 if (wordstart != start) {
00113                                         drawText(text,false,wordstart,start-wordstart);
00114                                         wordstart = start;
00115                                         width = 0;
00116                                 }
00117                                 wordstart++;
00118                                 font->drawString(this,text,start,1);
00119                                 break;
00120                         case Font::ESC: // ignore ANSI sequences except for colors
00121                                 if (wordstart != start) {
00122                                         drawText(text,false,wordstart,start-wordstart);
00123                                         wordstart = start;
00124                                         width = 0;
00125                                 }
00126                                 wordstart++;
00127                                 do {
00128                                         Size seqstart = start+1u;
00129                                         Char c;
00130                                         do {
00131                                                 start++;
00132                                                 wordstart++;
00133                                                 c = font->toSpecial(text[start]);
00134                                         } while (start < len && ((c >= '0' && c <= '9') || c == ';' || c == '['));
00135                                         if (c == 'm' && start < len) {
00136                                                 if (font->toSpecial(text[seqstart++]) != '[') break; /* FIXME: Clang/LLVM claims this comparison will never happen */
00137                                                 c = font->toSpecial(text[seqstart++]);
00138                                                 while (c != 'm') {
00139                                                         unsigned int param = 0;
00140                                                         if (c == ';') c = '0';
00141                                                         while (c != 'm' && c != ';') {
00142                                                                 param = param * 10u + (unsigned int)c - '0';
00143                                                                 c = font->toSpecial(text[seqstart++]);
00144                                                         }
00145                                                         const RGB bright = 0x00808080u;
00146                                                         const RGB intensity = (color&bright?~0u:~bright);
00147                                                         switch (param) {
00148                                                         case 0: setColor(Color::Black); break;
00149                                                         case 1: setColor(color | 0x00808080u); break;
00150                                                         case 30: setColor((Color::Black|bright) & intensity); break;
00151                                                         case 31: setColor(Color::Red & intensity); break;
00152                                                         case 32: setColor(Color::Green & intensity); break;
00153                                                         case 33: setColor(Color::Yellow & intensity); break;
00154                                                         case 34: setColor(Color::Blue & intensity); break;
00155                                                         case 35: setColor(Color::Magenta & intensity); break;
00156                                                         case 36: setColor(Color::Cyan & intensity); break;
00157                                                         case 37: setColor(Color::White & intensity); break;
00158                                                         default: break;
00159                                                         }
00160                                                 }
00161                                         }
00162                                 } while (0);
00163                         default:
00164                                 width += font->getWidth(text[start]);
00165                                 if (x > 0 && x+width > cw) gotoXY(0,y+font->getHeight());
00166                         }
00167                         start++;
00168                 }
00169                 if (wordstart != start) drawText(text,false,wordstart,start-wordstart);
00170                 return;
00171         }
00172 
00173         font->drawString(this,text,start,len);
00174 }
00175 
00176 bool ToplevelWindow::mouseDown(int x, int y, MouseButton button) {
00177         if (button == Left && x > 32 && x < width-6 && y > 4 && y < 31) {
00178                 dragx = x;
00179                 dragy = y;
00180                 mouseChild = NULL;
00181                 systemMenu->setVisible(false);
00182                 return true;
00183         } else if (button == Left && x < 32 && x > 6 && y > 4 && y < 31) {
00184                 mouseChild = NULL;
00185                 raise();
00186                 systemMenu->setVisible(!systemMenu->isVisible());
00187                 return true;
00188         }
00189         systemMenu->setVisible(false);
00190         BorderedWindow::mouseDown(x,y,button);
00191         return true;
00192 }
00193 
00194 Drawable::Drawable(int w, int h, RGB clear) :
00195         buffer(new RGB[w*h]),
00196         width(w), height(h),
00197         owner(true),
00198         color(Color::Black),
00199         font(NULL),
00200         lineWidth(1),
00201         tx(0), ty(0),
00202         cx(0), cy(0),
00203         cw(w), ch(h),
00204         x(0), y(0)
00205 {
00206         this->clear(clear);
00207 }
00208 
00209 Drawable::Drawable(Drawable &src, RGB clear) :
00210         buffer(new RGB[src.cw*src.ch]),
00211         width(src.cw), height(src.ch),
00212         owner(true),
00213         color(src.color),
00214         font(src.font),
00215         lineWidth(src.lineWidth),
00216         tx(0), ty(0),
00217         cx(0), cy(0),
00218         cw(src.cw), ch(src.ch),
00219         x(src.x), y(src.y)
00220 {
00221         if (clear != 0) {
00222                 this->clear(clear);
00223         } else {
00224                 for (unsigned int h = 0; (int)h < src.ch; h++) {
00225                         memcpy(buffer+(unsigned int)src.cw*h,src.buffer+(unsigned int)src.width*(h+(unsigned int)src.ty)+src.tx,4u*(unsigned int)src.cw);
00226                 }
00227         }
00228 }
00229 
00230 Drawable::Drawable(Drawable &src, int x, int y, int w, int h) :
00231         buffer(src.buffer),
00232         width(src.width), height(src.height),
00233         owner(false),
00234         color(src.color),
00235         font(src.font),
00236         lineWidth(src.lineWidth),
00237         tx(src.tx+x), ty(src.ty+y),
00238         cx(imax(imax(-x,src.cx-x),0)), cy(imax(imax(-y,src.cy-y),0)),
00239         cw(imax(0,imin(src.cw-x,w))), ch(imax(0,imin(src.ch-y,h))),
00240         x(imax(0,imin(src.tx-tx,cw))), y(imax(0,imin(src.ty-ty,cw)))
00241 {
00242 }
00243 
00244 Drawable::~Drawable()
00245 {
00246         if (owner) delete[] buffer;
00247 }
00248 
00249 void Drawable::clear(RGB clear)
00250 {
00251         for (int y = cy; y < ch; y++) {
00252                 for (int x = cx; x < cw; x++) {
00253                         buffer[(y+ty)*width+x+tx] = clear;
00254                 }
00255         }
00256 }
00257 
00258 void Drawable::drawLine(int x2, int y2)
00259 {
00260         int x0 = x2, x1 = x, y0 = y2, y1 = y;
00261         int dx = x2-x1, dy = y2-y1;
00262         drawPixel();
00263 
00264         if (abs(dx) > abs(dy)) {
00265                 if (x1 > x2) {
00266                         x = x2; x2 = x1; x1 = x;
00267                         y = y2; y2 = y1; y1 = y;
00268                 }
00269                 for (x = x1; x <= x2; x++) {
00270                         y = y1+(x-x1)*dy/dx-lineWidth/2;
00271                         for (int i = 0; i < lineWidth; i++, y++) {
00272                                 drawPixel();
00273                         }
00274                 }
00275         } else if (y1 != y2) {
00276                 if (y1 > y2) {
00277                         x = x2; x2 = x1; x1 = x;
00278                         y = y2; y2 = y1; y1 = y;
00279                 }
00280                 for (y = y1; y <= y2; y ++) {
00281                         x = x1+(y-y1)*dx/dy-lineWidth/2;
00282                         for (int i = 0; i < lineWidth; i++, x++) {
00283                                 drawPixel();
00284                         }
00285                 }
00286         }
00287 
00288         drawPixel(x0,y0);
00289 }
00290 
00291 void Drawable::drawCircle(int d) {
00292         int xo = 0, yo = d/2, rest = (d+1)/2-yo, x0 = x, y0 = y, rsq = d*d/4, lwo = lineWidth/2;
00293 
00294         while (xo <= yo) {
00295                 while (xo*xo+(2*yo-1)*(2*yo-1)/4 > rsq) yo--;
00296                 for (int i = 0, yow = yo+lwo; i < lineWidth; i++, yow--) {
00297                         drawPixel(x0+xo,y0-yow-rest);
00298                         drawPixel(x0+yow,y0-xo-rest);
00299                         drawPixel(x0+yow,y0+xo);
00300                         drawPixel(x0+xo,y0+yow);
00301 
00302                         drawPixel(x0-xo-rest,y0-yow-rest);
00303                         drawPixel(x0-yow-rest,y0-xo-rest);
00304                         drawPixel(x0-yow-rest,y0+xo);
00305                         drawPixel(x0-xo-rest,y0+yow);
00306                 }
00307 
00308                 xo++;
00309         }
00310         gotoXY(x0,y0);
00311 }
00312 
00313 void Drawable::drawRect(int w, int h)
00314 {
00315         gotoXY(x-lineWidth/2,y);
00316         drawLine(x+w+lineWidth-1,y);
00317         gotoXY(x-(lineWidth-1)/2,y);
00318         drawLine(x,y+h);
00319         gotoXY(x+(lineWidth-1)/2,y);
00320         drawLine(x-w-lineWidth+1,y);
00321         gotoXY(x+lineWidth/2,y);
00322         drawLine(x,y-h);
00323 }
00324 
00325 void Drawable::fill()
00326 {
00327         int x0 = x, xmin;
00328         RGB color = getPixel();
00329 
00330         if (color == this->color) return;
00331 
00332         for (x--; x >= 0 && getPixel() == color; x--) drawPixel();
00333         xmin = ++x;
00334         for (x = x0; x < cw && getPixel() == color; x++) drawPixel();
00335         y++;
00336         for (x--; x >= xmin; x--) {
00337                 if (getPixel() == color) fill();
00338                 y -= 2;
00339                 if (getPixel() == color) fill();
00340                 y += 2;
00341         }
00342         y--;
00343         x = x0;
00344 }
00345 
00346 void Drawable::fillCircle(int d)
00347 {
00348         int xo = 0, yo = d/2, rest = (d+1)/2-yo, x0 = x, y0 = y, rsq = d*d/4;
00349 
00350         while (xo <= yo) {
00351                 while (xo*xo+(2*yo-1)*(2*yo-1)/4 > rsq) yo--;
00352                 x = x0+xo;
00353                 for (y = y0-yo-rest; y <= y0+yo; y++) drawPixel();
00354                 x = x0-xo-rest;
00355                 for (y = y0-yo-rest; y <= y0+yo; y++) drawPixel();
00356 
00357                 y = y0-xo-rest;
00358                 for (x = x0-yo-rest; x <= x0+yo; x++) drawPixel();
00359                 y = y0+xo;
00360                 for (x = x0-yo-rest; x <= x0+yo; x++) drawPixel();
00361 
00362                 xo++;
00363         }
00364         gotoXY(x0,y0);
00365 }
00366 
00367 void Drawable::fillRect(int w, int h)
00368 {
00369         int x0 = x, y0 = y, w0 = w;
00370         for (; h > 0; h--, y++) {
00371                 for (x = x0, w = w0; w > 0; w--, x++) {
00372                         drawPixel();
00373                 }
00374         }
00375         gotoXY(x0,y0);
00376 }
00377 
00378 void Drawable::drawDrawable(Drawable &d, unsigned char alpha)
00379 {
00380         int scw = d.cw, sch = d.ch, w, h;
00381         RGB *src, *dest;
00382 
00383         for (h = imax(d.cy,-ty-y); h < sch && y+h < ch; h++) {
00384                 src = d.buffer+d.width*(h+d.ty)+d.tx;
00385                 dest = buffer+width*(y+ty+h)+tx+x;
00386                 for (w = imax(d.cx,-tx-x); w < scw && x+w < cw; w++) {
00387                         RGB srcb = src[w], destb = dest[w];
00388                         unsigned int sop = Color::A(srcb)*((unsigned int)alpha)/255;
00389                         unsigned int rop = Color::A(destb) + sop - Color::A(destb)*sop/255;
00390                         if (rop == 0) {
00391                                 dest[w] = Color::Transparent;
00392                         } else {
00393                                 unsigned int dop = Color::A(destb)*(255-sop)/255;
00394                                 unsigned int magval = ((destb&Color::MagentaMask)*dop+(srcb&Color::MagentaMask)*sop);
00395                                 dest[w] = (((magval&0xffff)/rop)&Color::BlueMask) |
00396                                         (((magval&0xffff0000)/rop)&Color::RedMask) |
00397                                         ((((destb&Color::GreenMask)*dop+(srcb&Color::GreenMask)*sop)/rop)&Color::GreenMask) |
00398                                         (rop<<Color::AlphaShift);
00399                         }
00400                 }
00401         }
00402 }
00403 
00404 void Drawable::drawText(const Char c, bool interpret)
00405 {
00406         if (interpret) {
00407                 switch (font->toSpecial(c)) {
00408                 case Font::CR: gotoXY(0,y); return;
00409                 case Font::LF: gotoXY(0,y+font->getHeight()); return;
00410                 case Font::BS: gotoXY(imax(0,x-font->getWidth()),y); return;
00411                 case Font::Tab: gotoXY((((int)(x/font->getWidth()/8))+1)*8*font->getWidth(),y); return;
00412                 default: break;
00413                 }
00414                 if (font->getWidth(c)+x > cw) gotoXY(0,y+font->getHeight());
00415         }
00416         font->drawChar(this,c);
00417 }
00418 
00419 void BitmapFont::drawChar(Drawable *d, const Char c) const {
00420 #define move(x) (ptr += ((x)+bit)/8-(((x)+bit)<0), bit = ((x)+bit+(((x)+bit)<0?8:0))%8)
00421         const unsigned char *ptr = bitmap;
00422         int bit = 0;
00423 
00424         if (c > last) return;
00425 
00426         if (char_position != NULL) {
00427                 ptr = char_position[c];
00428                 bit = 0;
00429         } else {
00430                 move(character_step*((int)c));
00431         }
00432 
00433         int rs = row_step;
00434         int w = (widths != NULL?widths[c]:width);
00435         int h = (ascents != NULL?ascents[c]:height);
00436         Drawable out(*d,d->getX(),d->getY()-ascent,w,h);
00437 
00438         if (rs == 0) rs = isign(col_step)*w;
00439         if (rs < 0) move(-rs*(h-1));
00440         if (col_step < 0) move(abs(rs)-1);
00441 
00442         for (int row = height-h; row < height; row++, move(rs-w*col_step)) {
00443                 for (int col = 0; col < w; col++, move(col_step)) {
00444                         if (!background_set ^ !(*ptr&(1<<bit)))
00445                                 out.drawPixel(col,row);
00446                 }
00447         }
00448         d->gotoXY(d->getX()+w,d->getY());
00449 #undef move
00450 }
00451 
00452 void Timer::check_to(unsigned int ticks) {
00453         if (ticks >= Timer::ticks) check(ticks - Timer::ticks);
00454 }
00455 
00456 void Timer::check(unsigned int ticks)
00457 {
00458         if (timers.empty()) {
00459                 Timer::ticks += ticks;
00460                 return;
00461         }
00462 
00463         if (Timer::ticks > (Timer::ticks+ticks)) {
00464                 ticks -= (unsigned int)(-(int)Timer::ticks) - 1u;
00465                 check((unsigned int)(-(int)Timer::ticks) - 1u);
00466         }
00467 
00468         std::multimap<unsigned int,Timer_Callback*,Timer::ltuint>::iterator old, i = timers.lower_bound(Timer::ticks+1);
00469         Timer::ticks += ticks;
00470 
00471         while (i != timers.end() && (*i).first <= Timer::ticks) {
00472                 Timer_Callback *c = (*i).second;
00473                 unsigned int time = (*i).first;
00474                 old = i;
00475                 ++i;
00476                 timers.erase(old);
00477                 unsigned int next = c->timerExpired(time);
00478                 if (next) add(c, time+next-Timer::ticks);
00479         }
00480 }
00481 
00482 void Timer::remove(const Timer_Callback *const timer)
00483 {
00484         if (timers.empty()) return;
00485 
00486         std::multimap<unsigned int,Timer_Callback*,Timer::ltuint>::iterator old, i = timers.begin();
00487 
00488         while (i != timers.end()) {
00489                 old = i;
00490                 ++i;
00491                 if ((*old).second == timer) timers.erase(old);
00492         }
00493 }
00494 
00495 unsigned int Timer::next()
00496 {
00497         if (timers.empty()) return 0;
00498 
00499         std::multimap<unsigned int,Timer_Callback*,Timer::ltuint>::iterator i = timers.upper_bound(ticks);
00500 
00501         if (i == timers.end()) return 0;
00502         return (*i).first-Timer::ticks;
00503 }
00504 
00505 std::multimap<unsigned int,Timer_Callback*,Timer::ltuint> Timer::timers;
00506 unsigned int Timer::ticks = 0;
00507 
00508 BitmapFont::BitmapFont(const unsigned char *data, int height, int ascent, bool owner,
00509                 int width, bool background_set,
00510                 int col_step, int row_step, int character_step, Char last,
00511                 const int *widths, const int *ascents, const unsigned char *const* char_position,
00512                 const Font::SpecialChar *special) :
00513                 bitmap(data),
00514                 width(width), height(height), ascent(ascent), widths(widths), ascents(ascents),
00515                 background_set(background_set), col_step(col_step), row_step(row_step),
00516                 character_step(character_step?character_step:abs((row_step?row_step:width*col_step)*height)),
00517                 char_position(char_position), special(special), owner(owner), last(last)
00518 {
00519 }
00520 
00521 BitmapFont::~BitmapFont() {
00522         if (owner) {
00523                 if (bitmap != NULL) delete bitmap;
00524                 if (ascents != NULL) delete ascents;
00525                 if (widths != NULL) delete widths;
00526                 if (special != NULL) delete special;
00527         }
00528 }
00529 
00530 Window::Window(Window *parent, int x, int y, int w, int h) :
00531         width(w), height(h),
00532         x(x), y(y),
00533         dirty(true),
00534         visible(true),
00535         parent(parent),
00536         mouseChild(NULL)
00537 {
00538         parent->addChild(this);
00539 }
00540 
00541 Window::Window() :
00542         width(0), height(0),
00543         x(0), y(0),
00544         dirty(false),
00545         visible(true),
00546         parent(NULL),
00547         mouseChild(NULL)
00548 {
00549 }
00550 
00551 
00552 Window::~Window()
00553 {
00554         while (!children.empty()) delete children.front();
00555         if (parent) parent->removeChild(this);
00556         if (parent && parent->mouseChild == this) parent->mouseChild = NULL;
00557 }
00558 
00559 void Window::addChild(Window *child)
00560 {
00561         children.push_back(child);
00562         setDirty();
00563 }
00564 
00565 void Window::removeChild(Window *child)
00566 {
00567         children.remove(child);
00568         setDirty();
00569 }
00570 
00571 void Window::move(int x, int y)
00572 {
00573         this->x = x;
00574         this->y = y;
00575         std::list<Window_Callback*>::iterator i = movehandlers.begin();
00576         bool end = (i == movehandlers.end());
00577         while (!end) {
00578                 Window_Callback *c = *i;
00579                 ++i;
00580                 end = (i == movehandlers.end());
00581                 c->windowMoved(this,x,y);
00582         }
00583         parent->setDirty();
00584 }
00585 
00586 void Window::resize(int w, int h)
00587 {
00588         this->width = w;
00589         this->height = h;
00590         setDirty();
00591 }
00592 
00593 void Window::paintAll(Drawable &d) const
00594 {
00595         paint(d);
00596         std::list<Window *>::const_iterator i = children.begin();
00597         while (i != children.end()) {
00598                 Window *child = *i;
00599                 ++i;
00600                 if (child->visible) {
00601                         Drawable *cd = new Drawable(d,child->x,child->y,child->width,child->height);
00602                         child->paintAll(*cd);
00603                         delete cd;
00604                 }
00605         }
00606 }
00607 
00608 bool Window::keyDown(const Key &key)
00609 {
00610         if (children.empty()) return false;
00611         if ((*children.rbegin())->keyDown(key)) return true;
00612         if (key.ctrl || key.alt || key.windows || key.special != Key::Tab) return false;
00613 
00614         if (key.shift) {
00615                 std::list<Window *>::reverse_iterator i = children.rbegin(), e = children.rend();
00616                 ++i;
00617                 while (i != e && !(*i)->raise()) ++i;
00618                 return i != e;
00619         } else {
00620                 std::list<Window *>::iterator i = children.begin(), e = children.end();
00621                 while (i != e && !(*i)->raise()) ++i;
00622                 return (i != e);
00623         }
00624 }
00625 
00626 bool Window::keyUp(const Key &key)
00627 {
00628         if (children.empty()) return false;
00629         return (*children.rbegin())->keyUp(key);
00630 }
00631 
00632 bool Window::mouseMoved(int x, int y)
00633 {
00634         std::list<Window *>::reverse_iterator i = children.rbegin();
00635         bool end = (i == children.rend());
00636         while (!end) {
00637                 Window *w = *i;
00638                 i++;
00639                 end = (i == children.rend());
00640                 if (w->visible && x >= w->x && x <= w->x+w->width
00641                         && y >= w->y && y <= w->y+w->height
00642                         && w->mouseMoved(x-w->x, y-w->y)) return true;
00643         }
00644         return false;
00645 }
00646 
00647 bool Window::mouseDragged(int x, int y, MouseButton button)
00648 {
00649         if (mouseChild == NULL) return false;
00650         return mouseChild->mouseDragged(x-mouseChild->x, y-mouseChild->y, button);
00651 }
00652 
00653 bool Window::mouseDown(int x, int y, MouseButton button)
00654 {
00655         std::list<Window *>::reverse_iterator i = children.rbegin();
00656         Window *last = NULL;
00657 
00658         while (i != children.rend()) {
00659                 Window *w = *i;
00660 
00661                 if (w->visible && x >= w->x && x <= w->x+w->width && y >= w->y && y <= w->y+w->height) {
00662                         mouseChild = last = w;
00663                         if (w->mouseDown(x-w->x, y-w->y, button) && w->raise()) {
00664                                 return true;
00665                         }
00666                 }
00667 
00668                 i++;
00669         }
00670 
00671         mouseChild = NULL;
00672         if (last != NULL) last->raise();
00673         return false;
00674 }
00675 
00676 bool Window::mouseUp(int x, int y, MouseButton button)
00677 {
00678         if (mouseChild == NULL) return false;
00679         return mouseChild->mouseUp(x-mouseChild->x, y-mouseChild->y, button);
00680 }
00681 
00682 bool Window::mouseClicked(int x, int y, MouseButton button)
00683 {
00684         if (mouseChild == NULL) return false;
00685         return mouseChild->mouseClicked(x-mouseChild->x, y-mouseChild->y, button);
00686 }
00687 
00688 bool Window::mouseDoubleClicked(int x, int y, MouseButton button)
00689 {
00690         if (mouseChild == NULL) return false;
00691         return mouseChild->mouseDoubleClicked(x-mouseChild->x, y-mouseChild->y, button);
00692 }
00693 
00694 bool BorderedWindow::mouseDown(int x, int y, MouseButton button)
00695 {
00696         mouseChild = NULL;
00697         if (x > width-border_right || y > width-border_bottom) return false;
00698         x -= border_left; y -= border_top;
00699         if (x < 0 || y < 0) return false;
00700         return Window::mouseDown(x,y,button);
00701 }
00702 
00703 bool BorderedWindow::mouseMoved(int x, int y)
00704 {
00705         if (x > width-border_right || y > width-border_bottom) return false;
00706         x -= border_left; y -= border_top;
00707         if (x < 0 || y < 0) return false;
00708         return Window::mouseMoved(x,y);
00709 }
00710 
00711 bool BorderedWindow::mouseDragged(int x, int y, MouseButton button)
00712 {
00713         if (x > width-border_right || y > width-border_bottom) return false;
00714         x -= border_left; y -= border_top;
00715         if (x < 0 || y < 0) return false;
00716         return Window::mouseDragged(x,y,button);
00717 }
00718 
00719 void ToplevelWindow::paint(Drawable &d) const
00720 {
00721         unsigned int mask = (systemMenu->isVisible()?Color::RedMask|Color::GreenMask|Color::BlueMask:0);
00722         d.clear(Color::Background);
00723 
00724         d.setColor(Color::Border);
00725         d.drawLine(0,height-1,width-1,height-1);
00726         d.drawLine(width-1,0,width-1,height-1);
00727 
00728         d.setColor(Color::Shadow3D);
00729         d.drawLine(0,0,width-2,0);
00730         d.drawLine(0,0,0,height-2);
00731         d.drawLine(0,height-2,width-2,height-2);
00732         d.drawLine(width-2,0,width-2,height-2);
00733 
00734         d.drawLine(5,4,width-7,4);
00735         d.drawLine(5,4,5,30);
00736 
00737         d.setColor(Color::Light3D);
00738         d.drawLine(1,1,width-3,1);
00739         d.drawLine(1,1,1,height-3);
00740 
00741         d.drawLine(5,31,width-6,31);
00742         d.drawLine(width-6,5,width-6,31);
00743 
00744         d.setColor(Color::Background3D^mask);
00745         d.fillRect(6,5,26,26);
00746         d.setColor(Color::Grey50^mask);
00747         d.fillRect(9,17,20,4);
00748         d.setColor(Color::Black^mask);
00749         d.fillRect(8,16,20,4);
00750         d.setColor(Color::White^mask);
00751         d.fillRect(9,17,18,2);
00752 
00753         d.setColor(Color::Border);
00754         d.drawLine(32,5,32,30);
00755 
00756         d.setColor(Color::Titlebar);
00757         d.fillRect(33,5,width-39,26);
00758 
00759         const Font *font = Font::getFont("title");
00760         d.setColor(Color::TitlebarText);
00761         d.setFont(font);
00762         d.drawText(31+(width-39-font->getWidth(title))/2,5+(26-font->getHeight())/2+font->getAscent(),title,false,0);
00763 }
00764 
00765 void Input::posToEnd(void) {
00766         pos = (GUI::Size)text.size();
00767         checkOffset();
00768 }
00769 
00770 void Input::paint(Drawable &d) const
00771 {
00772         d.clear(Color::EditableBackground);
00773 
00774         d.setColor(Color::Shadow3D);
00775         d.drawLine(0,0,width-2,0);
00776         d.drawLine(0,0,0,height-2);
00777 
00778         d.setColor(Color::Background3D);
00779         d.drawLine(1,height-2,width-2,height-2);
00780         d.drawLine(width-2,1,width-2,height-2);
00781 
00782         d.setColor(Color::Text);
00783         d.drawLine(1,1,width-3,1);
00784         d.drawLine(1,1,1,height-3);
00785 
00786         const Font *f = Font::getFont("input");
00787         d.setFont(f);
00788 
00789         Drawable d1(d,3,4,width-6,height-8);
00790         Drawable dr(d1,(multi?0:-offset),(multi?-offset:0),width-6+(multi?0:offset),height-8+(multi?offset:0));
00791 
00792         const Size start = imin(start_sel, end_sel), end = imax(start_sel, end_sel);
00793         dr.drawText(0,f->getAscent()+1,text,multi,0,start);
00794 
00795         int sx = dr.getX(), sy = dr.getY();
00796         dr.drawText(text, multi, start, end-start);
00797         int ex = dr.getX(), ey = dr.getY();
00798 
00799         if (sx != ex || sy != ey) {
00800                 dr.setColor(Color::SelectionBackground);
00801                 if (sy == ey) dr.fillRect(sx,sy-f->getAscent(),ex-sx,f->getHeight()+1);
00802                 else {
00803                         dr.fillRect(sx, sy-f->getAscent(),              width-sx+offset, f->getHeight() );
00804                         dr.fillRect(0,  sy-f->getAscent()+f->getHeight(), width+offset,    ey-sy-f->getHeight());
00805                         dr.fillRect(0,  ey-f->getAscent(),              ex,           f->getHeight()    );
00806                 }
00807                 dr.setColor(Color::SelectionForeground);
00808                 dr.drawText(sx, sy, text, multi, start, end-start);
00809         }
00810 
00811         dr.setColor(Color::Text);
00812 
00813         dr.drawText(text, multi, end);
00814 
00815         if (blink && hasFocus()) {
00816                 if (insert) dr.drawLine(posx,posy,posx,posy+f->getHeight()+1);
00817                 else dr.fillRect(posx,posy,f->getWidth(text[pos]),f->getHeight()+1);
00818         }
00819 }
00820 
00821 Size Input::findPos(int x, int y) {
00822         const Font *f = Font::getFont("input");
00823         if (multi) y += offset;
00824         else x += offset;
00825         y = (y-4) / f->getHeight();
00826         int line = 0;
00827         Size pos = 0;
00828         while (line < y && pos < text.size()) if (f->toSpecial(text[pos++]) == Font::LF) line++;
00829         Drawable d(width-6,1);
00830         d.setFont(f);
00831         while (pos <= text.size() && d.getY() == 0 && x > d.getX()) {
00832                 d.drawText(String(text), multi, pos, 1);
00833                 pos++;
00834         }
00835         if (pos > 0) pos--;
00836         return pos;
00837 }
00838 
00839 bool Input::mouseDown(int x, int y, MouseButton button)
00840 {
00841         if (button == Left || (button == Middle && start_sel == end_sel)) {
00842                 end_sel = start_sel = pos = findPos(x,y);
00843                 blink = true;
00844                 checkOffset();
00845         }
00846         if (button == Middle) keyDown(Key(0,Key::Insert,true,false,false,false));
00847         return true;
00848 }
00849 
00850 bool Input::mouseDragged(int x, int y, MouseButton button)
00851 {
00852         if (button == Left) {
00853                 end_sel = pos = findPos(x,y);
00854                 blink = true;
00855                 checkOffset();
00856         }
00857         return true;
00858 }
00859 
00860 bool Input::keyDown(const Key &key)
00861 {
00862         const Font *f = Font::getFont("input");
00863         switch (key.special) {
00864         case Key::None:
00865                 if (key.ctrl) {
00866                         switch (key.character) {
00867                         case 1:
00868                         case 'a':
00869                         case 'A':
00870                                 if (key.shift) {
00871                                         start_sel = end_sel = pos;
00872                                 } else {
00873                                         start_sel = 0;
00874                                         pos = end_sel = (Size)text.size();
00875                                 }
00876                                 break;
00877                         case 24:
00878                         case 'x':
00879                         case 'X':
00880                                 cutSelection();
00881                                 break;
00882                         case 3:
00883                         case 'c':
00884                         case 'C':
00885                                 copySelection();
00886                                 break;
00887                         case 22:
00888                         case 'v':
00889                         case 'V':
00890                                 pasteSelection();
00891                                 break;
00892                         default: printf("Ctrl-0x%x\n",key.character); break;
00893                         }
00894                         break;
00895                 }
00896                 if (start_sel != end_sel) clearSelection();
00897                 if (insert || pos >= text.size() ) text.insert(text.begin()+pos++,key.character);
00898                 else text[pos++] = key.character;
00899                 break;
00900         case Key::Left:
00901                 if (pos > 0) pos--;
00902                 break;
00903         case Key::Right:
00904                 if (pos < text.size()) pos++;
00905                 break;
00906         case Key::Down:
00907                 if (multi) pos = findPos(posx+3, posy-offset+f->getHeight()+4);
00908                 break;
00909         case Key::Up:
00910                 if (multi) pos = findPos(posx+3, posy-offset-f->getHeight()+4);
00911                 break;
00912         case Key::Home:
00913                 if (multi) {
00914                         while (pos > 0 && f->toSpecial(text[pos-1]) != Font::LF) pos--;
00915                 } else pos = 0;
00916                 break;
00917         case Key::End:
00918                 if (multi) {
00919                         while (pos < text.size() && f->toSpecial(text[pos]) != Font::LF) pos++;
00920                 } else pos = (Size)text.size();
00921                 break;
00922         case Key::Backspace:
00923                 if (!key.shift && start_sel != end_sel) clearSelection();
00924                 else if (pos > 0) text.erase(text.begin()+ --pos);
00925                 break;
00926         case Key::Delete:
00927                 if (key.shift) cutSelection();
00928                 else if (start_sel != end_sel) clearSelection();
00929                 else if (pos < text.size()) text.erase(text.begin()+pos);
00930                 break;
00931         case Key::Insert:
00932                 if (key.ctrl) copySelection();
00933                 else if (key.shift) pasteSelection();
00934                 else insert = !insert;
00935                 break;
00936         case Key::Enter:
00937                 if (multi) {
00938                         if (start_sel != end_sel) clearSelection();
00939                         if (insert || pos >= text.size() ) text.insert(text.begin()+pos++,f->fromSpecial(Font::LF));
00940                         else text[pos++] = f->fromSpecial(Font::LF);
00941                 } else executeAction(text);
00942                 break;
00943         case Key::Tab:
00944                 if (multi) {
00945                         if (start_sel != end_sel) clearSelection();
00946                         if (insert || pos >= text.size() ) text.insert(text.begin()+pos++,f->fromSpecial(Font::Tab));
00947                         else text[pos++] = f->fromSpecial(Font::Tab);
00948                 } else return false;
00949                 break;
00950         default:
00951                 return false;
00952         }
00953         if (!key.ctrl) {
00954                 if (!key.shift || key.special == Key::None) start_sel = end_sel = pos;
00955                 else end_sel = pos;
00956         }
00957         checkOffset();
00958         blink = true;
00959         return true;
00960 }
00961 
00962 void BorderedWindow::paintAll(Drawable &d) const
00963 {
00964         this->paint(d);
00965         Drawable dchild(d,border_left,border_top,width-border_left-border_right,height-border_top-border_bottom);
00966         for (std::list<Window *>::const_iterator i = children.begin(); i != children.end(); ++i) {
00967                 Window *child = *i;
00968                 if (child->isVisible()) {
00969                         Drawable cd(dchild,child->getX(),child->getY(),child->getWidth(),child->getHeight());
00970                         child->paintAll(cd);
00971                 }
00972         }
00973 }
00974 
00975 void Button::paint(Drawable &d) const
00976 {
00977         int offset = -1;
00978 
00979         if (hasFocus()) {
00980                 offset = 0;
00981                 d.setColor(Color::Border);
00982                 d.drawLine(0,0,width,0);
00983                 d.drawLine(0,0,0,height);
00984 
00985                 d.drawLine(0,height-1,width,height-1);
00986                 d.drawLine(width-1,0,width-1,height);
00987         }
00988 
00989         d.setColor(Color::Background3D);
00990         d.fillRect(2,2,width-4,height-4);
00991 
00992         if (pressed) {
00993                 d.setColor(Color::Shadow3D);
00994 
00995                 d.drawLine(1+offset,1+offset,width-2-offset,1+offset);
00996                 d.drawLine(1+offset,1+offset,1+offset,height-2-offset);
00997         } else {
00998                 d.setColor(Color::Background3D);
00999 
01000                 d.drawLine(1+offset,1+offset,width-3-offset,1+offset);
01001                 d.drawLine(1+offset,1+offset,1+offset,height-3-offset);
01002 
01003                 d.setColor(Color::Light3D);
01004 
01005                 d.drawLine(2+offset,2+offset,width-4-offset,2+offset);
01006                 d.drawLine(2+offset,2+offset,2+offset,height-4-offset);
01007 
01008                 d.setColor(Color::Shadow3D);
01009 
01010                 d.drawLine(2+offset,height-3-offset,width-2-offset,height-3-offset);
01011                 d.drawLine(width-3-offset,2+offset,width-3-offset,height-2-offset);
01012 
01013                 d.setColor(Color::Border);
01014 
01015                 d.drawLine(width-2-offset,1+offset,width-2-offset,height-2-offset);
01016                 d.drawLine(1+offset,height-2-offset,width-2-offset,height-2-offset);
01017         }
01018 }
01019 
01020 bool Checkbox::keyDown(const Key &key)
01021 {
01022         switch (key.special) {
01023         case Key::None:
01024                 if (key.character != ' ') return false;
01025         case Key::Enter:
01026                 break;
01027         default: return false;
01028         }
01029         mouseDown(0,0,Left);
01030         return true;
01031 }
01032 
01033 bool Checkbox::keyUp(const Key &key)
01034 {
01035         if (key.ctrl || key.alt || key.windows || (key.character != ' ' && key.special != Key::Enter)) return false;
01036         mouseUp(0,0,Left);
01037         mouseClicked(0,0,Left);
01038         return true;
01039 }
01040 
01041 void Checkbox::paint(Drawable &d) const
01042 {
01043         d.setColor(Color::Background3D);
01044         d.fillRect(2,(height/2)-7,14,14);
01045 
01046         d.setColor(Color::Shadow3D);
01047         d.drawLine(2,(height/2)-7,13,(height/2)-7);
01048         d.drawLine(2,(height/2)-7,2,(height/2)+5);
01049 
01050         d.setColor(Color::Light3D);
01051         d.drawLine(2,(height/2)+5,14,(height/2)+5);
01052         d.drawLine(14,(height/2)-7,14,(height/2)+5);
01053 
01054         d.setColor(Color::EditableBackground);
01055         d.fillRect(4,(height/2)-5,9,9);
01056 
01057         d.setColor(Color::Border);
01058         d.drawLine(3,(height/2)-6,12,(height/2)-6);
01059         d.drawLine(3,(height/2)-6,3,(height/2)+4);
01060 
01061         if (checked) {
01062                 d.setColor(Color::Text);
01063                 d.drawLine(5,(height/2)-2,7,(height/2)  );
01064                 d.drawLine(11,(height/2)-4);
01065                 d.drawLine(5,(height/2)-1,7,(height/2)+1);
01066                 d.drawLine(11,(height/2)-3);
01067                 d.drawLine(5,(height/2)  ,7,(height/2)+2);
01068                 d.drawLine(11,(height/2)-2);
01069         }
01070 }
01071 
01072 Radiobox::Radiobox(Frame *parent, int x, int y, int w, int h) : BorderedWindow(static_cast<Window *>(parent),x,y,w,h,16,0,0,0), ActionEventSource("GUI::Radiobox"), checked(0)
01073 {
01074          addActionHandler(parent);
01075 }
01076 
01077 bool Radiobox::keyDown(const Key &key)
01078 {
01079         switch (key.special) {
01080         case Key::None:
01081                 if (key.character != ' ') return false;
01082         case Key::Enter:
01083                 break;
01084         default: return false;
01085         }
01086         mouseDown(0,0,Left);
01087         return true;
01088 }
01089 
01090 bool Radiobox::keyUp(const Key &key)
01091 {
01092         if (key.ctrl || key.alt || key.windows || (key.character != ' ' && key.special != Key::Enter)) return false;
01093         mouseUp(0,0,Left);
01094         mouseClicked(0,0,Left);
01095         return true;
01096 }
01097 
01098 void Radiobox::paint(Drawable &d) const
01099 {
01100         d.setColor(Color::Light3D);
01101         d.drawLine(6,(height/2)+6,9,(height/2)+6);
01102         d.drawLine(4,(height/2)+5,11,(height/2)+5);
01103         d.drawLine(13,(height/2)-1,13,(height/2)+2);
01104         d.drawLine(12,(height/2)-2,12,(height/2)+4);
01105 
01106         d.setColor(Color::Background3D);
01107         d.drawLine(6,(height/2)+5,9,(height/2)+5);
01108         d.drawLine(4,(height/2)+4,11,(height/2)+4);
01109         d.drawLine(12,(height/2)-1,12,(height/2)+2);
01110         d.drawLine(11,(height/2)-2,11,(height/2)+4);
01111 
01112         d.setColor(Color::Shadow3D);
01113         d.drawLine(6,(height/2)-5,9,(height/2)-5);
01114         d.drawLine(4,(height/2)-4,11,(height/2)-4);
01115         d.drawLine(2,(height/2)-1,2,(height/2)+2);
01116         d.drawLine(3,(height/2)-3,3,(height/2)+4);
01117 
01118         d.setColor(Color::Border);
01119         d.drawLine(6,(height/2)-4,9,(height/2)-4);
01120         d.drawLine(4,(height/2)-3,11,(height/2)-3);
01121         d.drawLine(3,(height/2)-1,3,(height/2)+2);
01122         d.drawLine(4,(height/2)-3,4,(height/2)+3);
01123 
01124         d.setColor(Color::EditableBackground);
01125         d.fillRect(5,(height/2)-2,6,6);
01126         d.fillRect(4,(height/2)-1,8,4);
01127         d.fillRect(6,(height/2)-3,4,8);
01128 
01129         if (checked) {
01130                 d.setColor(Color::Text);
01131                 d.fillRect(6,(height/2),4,2);
01132                 d.fillRect(7,(height/2)-1,2,4);
01133         }
01134 }
01135 
01136 void Menu::paint(Drawable &d) const
01137 {
01138         d.clear(Color::Background3D);
01139 
01140         d.setColor(Color::Border);
01141         d.drawLine(0,height-1,width-1,height-1);
01142         d.drawLine(width-1,0,width-1,height-1);
01143 
01144         d.setColor(Color::Shadow3D);
01145         d.drawLine(0,0,width-2,0);
01146         d.drawLine(0,0,0,height-2);
01147         d.drawLine(0,height-2,width-2,height-2);
01148         d.drawLine(width-2,0,width-2,height-2);
01149 
01150         d.setColor(Color::Light3D);
01151         d.drawLine(1,1,width-3,1);
01152         d.drawLine(1,1,1,height-3);
01153 
01154         d.setFont(Font::getFont("menu"));
01155         const int asc = Font::getFont("menu")->getAscent()+1;
01156         const int height = Font::getFont("menu")->getHeight()+2;
01157         int y = asc+3;
01158         int index = 0;
01159         for (std::vector<String>::const_iterator i = items.begin(); i != items.end(); ++i) {
01160                 if ((*i).empty()) {
01161                         d.setColor(Color::Shadow3D);
01162                         d.drawLine(4,y-asc+6,width-5,y-asc+6);
01163                         d.setColor(Color::Light3D);
01164                         d.drawLine(4,y-asc+7,width-5,y-asc+7);
01165                         y += 12;
01166                 } else {
01167                         if (index == selected && hasFocus()) {
01168                                 d.setColor(Color::SelectionBackground);
01169                                 d.fillRect(3,y-asc,width-6,height);
01170                                 d.setColor(Color::SelectionForeground);
01171                         } else {
01172                                 d.setColor(Color::Text);
01173                         }
01174                         d.drawText(20,y,(*i),false,0);
01175                         y += height;
01176                 }
01177                 index++;
01178         }
01179 }
01180 
01181 void Menubar::paint(Drawable &d) const
01182 {
01183         const Font *f = Font::getFont("menu");
01184 
01185         d.setColor(Color::Light3D);
01186         d.drawLine(0,height-1,width-1,height-1);
01187         d.setColor(Color::Shadow3D);
01188         d.drawLine(0,height-2,width-1,height-2);
01189 
01190         d.gotoXY(7,f->getAscent()+2);
01191 
01192         int index = 0;
01193         for (std::vector<Menu*>::const_iterator i = menus.begin(); i != menus.end(); ++i, ++index) {
01194                 if (index == selected && (*i)->isVisible()) {
01195                         int w = f->getWidth((*i)->getName());
01196                         d.setColor(Color::SelectionBackground);
01197                         d.fillRect(d.getX()-7,0,w+14,height-2);
01198                         d.setColor(Color::SelectionForeground);
01199                         d.gotoXY(d.getX()+7,f->getAscent()+2);
01200                 } else {
01201                         d.setColor(Color::Text);
01202                 }
01203                 d.drawText((*i)->getName(),false);
01204                 d.gotoXY(d.getX()+14,f->getAscent()+2);
01205         }
01206 }
01207 
01208 bool Button::keyDown(const Key &key)
01209 {
01210         switch (key.special) {
01211         case Key::None:
01212                 if (key.character != ' ') return false;
01213         case Key::Enter:
01214                 break;
01215         default: return false;
01216         }
01217         mouseDown(0,0,Left);
01218         return true;
01219 }
01220 
01221 bool Button::keyUp(const Key &key)
01222 {
01223         if (key.ctrl || key.alt || key.windows || (key.character != ' ' && key.special != Key::Enter)) return false;
01224         mouseUp(0,0,Left);
01225         mouseClicked(0,0,Left);
01226         return true;
01227 }
01228 
01229 void Frame::paint(Drawable &d) const {
01230         const Font *f = Font::getFont("default");
01231         const int top = (label.empty()?1:f->getAscent()/2+1);
01232 
01233         d.setColor(Color::Shadow3D);
01234         d.drawLine(1,height-2,1,top);
01235         d.drawLine(8,top);
01236         d.drawLine((label.empty()?8:f->getWidth(label)+14),top,width-2,top);
01237         d.drawLine(2,height-3,width-3,height-3);
01238         d.drawLine(width-3,top+1);
01239         
01240         d.setColor(Color::Light3D);
01241         d.drawLine(2,height-3,2,top+1);
01242         d.drawLine(8,top+1);
01243         d.drawLine((label.empty()?8:f->getWidth(label)+14),top+1,width-3,top+1);
01244         d.drawLine(2,height-2,width-2,height-2);
01245         d.drawLine(width-2,top+1);
01246 
01247         d.setColor(Color::Text);
01248         d.drawText(11,f->getAscent()+1,label,false,0);
01249 }
01250 
01251 Screen *Window::getScreen() { return (parent == NULL?dynamic_cast<Screen*>(this):parent->getScreen()); }
01252 
01253 Screen::Screen(unsigned int width, unsigned int height) :
01254         Window(),
01255         buffer(new Drawable((int)width, (int)height))
01256 {
01257         this->width = (int)width;
01258         this->height = (int)height;
01259 }
01260 
01261 Screen::Screen(Drawable *d) :
01262         Window(),
01263         buffer(d)
01264 {
01265         this->width = d->getClipWidth();
01266         this->height = d->getClipHeight();
01267 }
01268 
01269 Screen::~Screen()
01270 {
01271 }
01272 
01273 void Screen::paint(Drawable &d) const
01274 {
01275         d.clear(Color::Transparent);
01276 }
01277 
01278 unsigned int Screen::update(void *surface, unsigned int ticks)
01279 {
01280     (void)ticks;//UNUSED
01281         paintAll(*buffer);
01282         RGB *buf = buffer->buffer;
01283         for (y = 0; y < height; y++) {
01284                 for (x = 0; x < width; x++, buf++) {
01285                         RGB sval = surfaceToRGB(surface);
01286                         RGB bval = *buf;
01287                         unsigned int a = Color::A(bval);
01288                         bval = ((((sval&Color::MagentaMask)*a+(bval&Color::MagentaMask)*(256-a))>>8)&Color::MagentaMask)
01289                                 | ((((sval&Color::GreenMask)*a+(bval&Color::GreenMask)*(256-a))>>8)&Color::GreenMask);
01290                         rgbToSurface(bval, &surface);
01291                 }
01292         }
01293 
01294         return Timer::next();
01295 }
01296 
01297 void Screen::move(int x, int y)
01298 {
01299     (void)x;//UNUSED
01300     (void)y;//UNUSED
01301 }
01302 
01303 void Screen::resize(int w, int h)
01304 {
01305     (void)w;//UNUSED
01306     (void)h;//UNUSED
01307 }
01308 
01309 #ifdef TESTING
01310 static void test(Drawable &d) {
01311         const int width = d.getClipWidth();
01312         const int height = d.getClipHeight();
01313 
01314         d.clear(Color::rgba(0,0,255,128));
01315 
01316         d.setColor(Color::Black);
01317         for (int x = 0; x < width; x += 10) d.drawLine(x,0,x,height);
01318         for (int y = 0; y < height; y += 10) d.drawLine(0,y,width,y);
01319 
01320         d.setColor(Color::Red);
01321         for (int x = 10; x <= 130 ; x += 10) {
01322                 d.drawLine(x,10,70,70);
01323                 d.drawLine(x,130);
01324         }
01325         for (int y = 10; y <= 130 ; y += 10) {
01326                 d.drawLine(10,y,70,70);
01327                 d.drawLine(130,y);
01328         }
01329 
01330         d.setColor(Color::Yellow);
01331         d.fillRect(150,10,30,30);
01332         d.setColor(Color::Blue);
01333         d.drawRect(30,30);
01334 
01335         d.drawRect(150,60,30,30);
01336         d.setColor(Color::Yellow);
01337         d.fillRect(30,30);
01338 
01339         for (int x = 0; x <= 100 ; x += 10) {
01340                 d.setColor(Color::rgba(0xff,0x00,0xff,(255*x/100)&255));
01341                 d.fillRect(200+2*x,0,20,20);
01342         }
01343 
01344         d.setColor(Color::Yellow);
01345         d.fillCircle(210,60,40);
01346         d.setColor(Color::Blue);
01347         d.drawCircle(40);
01348 
01349         d.drawCircle(210,110,40);
01350         d.setColor(Color::Yellow);
01351         d.fillCircle(40);
01352 
01353         d.setColor(Color::rgba(0,0,255,128));
01354         d.fillRect(251,41,9,59);
01355         d.fillRect(251,41,59,9);
01356         d.fillRect(301,41,9,59);
01357         d.fillRect(291,91,19,9);
01358         d.fillRect(291,51,9,49);
01359         d.fillRect(261,51,39,9);
01360         d.fillRect(261,51,9,49);
01361         d.fillRect(261,91,29,9);
01362         d.fillRect(281,61,9,39);
01363         d.fillRect(271,61,19,9);
01364         d.fillRect(271,61,9,29);
01365         d.fillRect(241,41,9,59);
01366         d.fillRect(241,41,19,9);
01367         d.fillRect(241,91,19,9);
01368         d.setColor(Color::rgba(255,0,0,128));
01369         d.fill(255,64);
01370 
01371         d.setColor(Color::Green);
01372         Drawable(d,500,355,30,30).fillCircle(65);
01373 
01374         for (int i = 0; i <= 100; i += 10) {
01375                 Drawable(d,25,155+i*3,420,30).drawDrawable(0,0,d,255*i/100);
01376         }
01377 
01378         d.setColor(Color::White);
01379         d.setFont(Font::getFont("VGA14"));
01380         d.drawText(270,110,"GUI:: Test Program\n");
01381         d.drawText("Still testing\tTable\n");
01382         d.drawText("More of...\tTable\n");
01383         d.drawText("Overwrite\rXXXXXXXXX\n");
01384         d.drawText("Fake int'l chars: O\b/e\b\"\n");
01385         d.drawText("Real ones: \211\222\234\345\246\321");
01386 }
01387 #else
01388 static void test(Drawable &d) { (void)d; }
01389 #endif
01390 
01391 
01392 void ScreenRGB32le::paint(Drawable &d) const
01393 {
01394         parent->paint(d);
01395         test(d);
01396 }
01397 
01398 static MouseButton SDL_to_GUI(const int button)
01399 {
01400         switch (button) {
01401         case SDL_BUTTON_LEFT:      return GUI::Left;
01402         case SDL_BUTTON_RIGHT:     return GUI::Right;
01403         case SDL_BUTTON_MIDDLE:    return GUI::Middle;
01404         case SDL_BUTTON_WHEELUP:   return GUI::WheelUp;
01405         case SDL_BUTTON_WHEELDOWN: return GUI::WheelDown;
01406         default: return GUI::NoButton;
01407         }
01408 }
01409 
01410 static const Key SDL_to_GUI(const SDL_keysym &key)
01411 {
01412         GUI::Key::Special ksym = GUI::Key::None;
01413         switch (key.sym) {
01414         case SDLK_ESCAPE: ksym = GUI::Key::Escape; break;
01415         case SDLK_BACKSPACE: ksym = GUI::Key::Backspace; break;
01416         case SDLK_TAB: ksym = GUI::Key::Tab; break;
01417         case SDLK_LEFT: ksym = GUI::Key::Left; break;
01418         case SDLK_RIGHT: ksym = GUI::Key::Right; break;
01419         case SDLK_UP: ksym = GUI::Key::Up; break;
01420         case SDLK_DOWN: ksym = GUI::Key::Down; break;
01421         case SDLK_HOME: ksym = GUI::Key::Home; break;
01422         case SDLK_END: ksym = GUI::Key::End; break;
01423         case SDLK_DELETE: ksym = GUI::Key::Delete; break;
01424         case SDLK_INSERT: ksym = GUI::Key::Insert; break;
01425         case SDLK_RETURN: ksym = GUI::Key::Enter; break;
01426         case SDLK_MENU: ksym = GUI::Key::Menu; break;
01427         case SDLK_PAGEUP: ksym = GUI::Key::PageUp; break;
01428         case SDLK_PAGEDOWN: ksym = GUI::Key::PageDown; break;
01429         case SDLK_PRINT: ksym = GUI::Key::Print; break;
01430         case SDLK_PAUSE: ksym = GUI::Key::Pause; break;
01431         case SDLK_BREAK: ksym = GUI::Key::Break; break;
01432         case SDLK_CAPSLOCK: ksym = GUI::Key::CapsLock; break;
01433         case SDLK_NUMLOCK: ksym = GUI::Key::NumLock; break;
01434         case SDLK_SCROLLOCK: ksym = GUI::Key::ScrollLock; break;
01435         case SDLK_F1:case SDLK_F2:case SDLK_F3:case SDLK_F4:case SDLK_F5:case SDLK_F6:
01436         case SDLK_F7:case SDLK_F8:case SDLK_F9:case SDLK_F10:case SDLK_F11:case SDLK_F12:
01437                 ksym = (GUI::Key::Special)(GUI::Key::F1 + key.sym-SDLK_F1);
01438         default: break;
01439         }
01440         return Key(key.unicode, ksym,
01441                 (key.mod&KMOD_SHIFT)>0,
01442                 (key.mod&KMOD_CTRL)>0,
01443                 (key.mod&KMOD_ALT)>0,
01444                 (key.mod&KMOD_META)>0);
01445 }
01446 
01448 class SDL_Drawable : public Drawable {
01449 protected:
01450         SDL_Surface *const surface;
01451 
01452 public:
01453         SDL_Drawable(int width, int height, RGB clear = Color::Transparent) : Drawable(width, height, clear), surface(SDL_CreateRGBSurfaceFrom(buffer, width, height, 32, width*4, Color::RedMask, Color::GreenMask, Color::BlueMask, Color::AlphaMask)) {
01454             surface->flags |= SDL_SRCALPHA;
01455         }
01456 
01457         ~SDL_Drawable() {
01458             SDL_FreeSurface(surface);
01459         }
01460 
01461         void update(SDL_Surface *dest) const {
01462             SDL_BlitSurface(surface, NULL, dest, NULL);
01463         }
01464 };
01465 
01466 ScreenSDL::ScreenSDL(SDL_Surface *surface) : Screen(new SDL_Drawable(surface->w, surface->h)), surface(surface), downx(0), downy(0), lastclick(0), lastdown(0) {
01467         current_abs_time = start_abs_time = SDL_GetTicks();
01468         current_time = 0;
01469 }
01470 
01471 Ticks ScreenSDL::update(Ticks ticks)
01472 {
01473         Timer::check_to(ticks);
01474         paintAll(*buffer);
01475         static_cast<SDL_Drawable*>(buffer)->update(surface);
01476 
01477         return Timer::next();
01478 }
01479 
01480 void ScreenSDL::watchTime() {
01481         current_abs_time = SDL_GetTicks();
01482         current_time = current_abs_time - start_abs_time;
01483 }
01484 
01485 void ScreenSDL::paint(Drawable &d) const {
01486         d.clear(Color::Transparent);
01487         test(d);
01488 }
01489 
01490 bool ScreenSDL::event(const SDL_Event &event) {
01491         bool rc;
01492 
01493         switch (event.type) {
01494         case SDL_KEYUP: {
01495                 const Key &key = SDL_to_GUI(event.key.keysym);
01496                 if (key.special == GUI::Key::None && key.character == 0) break;
01497                 if (key.special == GUI::Key::CapsLock || key.special == GUI::Key::NumLock) keyDown(key);
01498                 return keyUp(key);
01499         }
01500         case SDL_KEYDOWN: {
01501                 const Key &key = SDL_to_GUI(event.key.keysym);
01502                 if (key.special == GUI::Key::None && key.character == 0) break;
01503                 rc = keyDown(key);
01504                 if (key.special == GUI::Key::CapsLock || key.special == GUI::Key::NumLock) keyUp(key);
01505                 return rc;
01506         }
01507         case SDL_MOUSEMOTION:
01508                 if (event.motion.state) {
01509                         if (abs(event.motion.x-downx) <= 10 && abs(event.motion.y-downy) <= 10)
01510                                 break;
01511                         downx = -11; downy = -11;
01512                         if (event.motion.state&SDL_BUTTON(1))
01513                                 return mouseDragged(event.motion.x, event.motion.y, GUI::Left);
01514                         else if (event.motion.state&SDL_BUTTON(2))
01515                                 return mouseDragged(event.motion.x, event.motion.y, GUI::Middle);
01516                         else if (event.motion.state&SDL_BUTTON(3))
01517                                 return mouseDragged(event.motion.x, event.motion.y, GUI::Right);
01518                         break;
01519                 }
01520 
01521                 return mouseMoved(event.motion.x, event.motion.y);
01522 
01523         case SDL_MOUSEBUTTONDOWN:
01524                 rc = mouseDown(event.button.x, event.button.y, SDL_to_GUI(event.button.button));
01525                 if (abs(event.button.x-downx) > 10 || abs(event.button.y-downy) > 10) lastclick = 0;
01526                 downx = event.button.x; downy = event.button.y;
01527                 lastdown = GUI::Timer::now();
01528                 return rc;
01529 
01530         case SDL_MOUSEBUTTONUP:
01531                 rc = mouseUp(event.button.x, event.button.y, SDL_to_GUI(event.button.button));
01532                 if (lastdown != 0 && abs(event.button.x-downx) < 10 && abs(event.button.y-downy) < 10) {
01533                         if (lastclick == 0 || (GUI::Timer::now()-lastclick) > 200) {
01534                                 lastclick = GUI::Timer::now();
01535                                 rc |= mouseClicked(downx, downy, SDL_to_GUI(event.button.button));
01536                         } else if (lastclick != 0) {
01537                                 rc |= mouseDoubleClicked(downx, downy, SDL_to_GUI(event.button.button));
01538                                 lastclick = 0;
01539                         } else {
01540                                 lastclick = 0;
01541                         }
01542                 } else {
01543                         lastclick = 0;
01544                 }
01545                 lastdown = 0;
01546                 return rc;
01547         }
01548 
01549         return false;
01550 }
01551 
01552 } /* end namespace GUI */
01553 #endif /* !C_SDL2 */