Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

pgwidget.cpp

Go to the documentation of this file.
00001 /*
00002    ParaGUI - crossplatform widgetset
00003    Copyright (C) 2000,2001,2002  Alexander Pipelka
00004  
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009  
00010    This library 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 GNU
00013    Library General Public License for more details.
00014  
00015    You should have received a copy of the GNU Library General Public
00016    License along with this library; if not, write to the Free
00017    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018  
00019    Alexander Pipelka
00020    pipelka@teleweb.at
00021  
00022    Last Update:      $Author: mbickel $
00023    Update Date:      $Date: 2008-04-20 16:44:33 $
00024    Source File:      $Source: /home/cvspsrv/cvsroot/games/asc/source/libs/paragui/src/widgets/pgwidget.cpp,v $
00025    CVS/RCS Revision: $Revision: 1.3 $
00026    Status:           $State: Exp $
00027  */
00028 
00029 #include <cstring>
00030 #include <stdarg.h>
00031 
00032 #include "pgwidget.h"
00033 #include "pgapplication.h"
00034 #include "pglog.h"
00035 #include "pgdraw.h"
00036 #include "pglayout.h"
00037 #include "pgtheme.h"
00038 #include "pgeventsupplier.h"
00039 
00040 #include "propstrings_priv.h"
00041 
00042 #define TXT_HEIGHT_UNDEF 0xFFFF
00043 
00044 
00045 //bool PG_Widget::bBulkUpdate = false;
00046 PG_RectList PG_Widget::widgetList;
00047 int PG_Widget::my_ObjectCounter = 0;
00048 
00049 class PG_WidgetDataInternal {
00050 public:
00051         PG_WidgetDataInternal() : modalstatus(0), inDestruct(false), inMouseLeave(false), font(NULL), dirtyUpdate(false), id(-1),
00052                         transparency(0), quitModalLoop(false), visible(false), hidden(false), firstredraw(true),
00053                         childList(NULL), haveTooltip(false), fadeSteps(10), mouseInside(false), userdata(NULL),
00054          userdatasize(0), widthText(TXT_HEIGHT_UNDEF), heightText(TXT_HEIGHT_UNDEF), widgetParent(NULL), hotkeyModifier(-1), hotkey(0) {
00055                 updateOverlappingSiblings = PG_Application::GetUpdateOverlappingSiblings();
00056         };
00057 
00058         int modalstatus;
00059         bool inDestruct;
00060         bool inMouseLeave;
00061         PG_Font* font;
00062         bool dirtyUpdate;
00063         int id;
00064         Uint8 transparency;
00065         bool quitModalLoop;
00066         bool visible;
00067         bool hidden;
00068         bool firstredraw;
00069         PG_RectList* childList;
00070         bool haveTooltip;
00071         int fadeSteps;
00072         bool mouseInside;
00073         char* userdata;
00074         int userdatasize;
00075         Uint16 widthText;
00076         Uint16 heightText;
00077 
00078         PG_Widget* widgetParent;
00079         PG_Point ptDragStart;
00080         PG_Rect rectClip;
00081         bool havesurface;
00082         std::string name;
00083         bool updateOverlappingSiblings;
00084    int hotkeyModifier;
00085    PG_Char hotkey;
00086 
00087 };
00088 
00089 PG_Widget::PG_Widget(PG_Widget* parent, const PG_Rect& rect, bool bObjectSurface) :
00090 PG_Rect(rect), my_srfObject(NULL), _mid(new PG_WidgetDataInternal) {
00091 
00092         _mid->havesurface = bObjectSurface;
00093 
00094         //Set default font
00095         if(PG_Application::DefaultFont != NULL) {
00096                 _mid->font = new PG_Font(
00097                                  PG_Application::DefaultFont->GetName(),
00098                                  PG_Application::DefaultFont->GetSize());
00099         } else {
00100                 PG_LogWRN("Unable to get default font! Did you load a theme ?");
00101         }
00102 
00103         //my_srfScreen = PG_Application::GetScreen();
00104 
00105         if(_mid->havesurface) {
00106                 my_srfObject = PG_Draw::CreateRGBSurface(w, h);
00107         }
00108 
00109         // ??? - How can i do this better - ???
00110         char buffer[15];
00111         sprintf(buffer, "Object%d", ++my_ObjectCounter);
00112         _mid->name = buffer;
00113 
00114         // default border colors
00115         my_colorBorder[0][0].r = 255;
00116         my_colorBorder[0][0].g = 255;
00117         my_colorBorder[0][0].b = 255;
00118 
00119         my_colorBorder[0][1].r = 239;
00120         my_colorBorder[0][1].g = 239;
00121         my_colorBorder[0][1].b = 239;
00122 
00123         my_colorBorder[1][0].r = 89;
00124         my_colorBorder[1][0].g = 89;
00125         my_colorBorder[1][0].b = 89;
00126 
00127         my_colorBorder[1][1].r = 134;
00128         my_colorBorder[1][1].g = 134;
00129         my_colorBorder[1][1].b = 134;
00130 
00131         if (parent) {
00132                 //my_xpos = _mid->widgetParent->my_xpos + my_xpos;
00133                 //my_ypos = _mid->widgetParent->my_ypos + my_ypos;
00134                 parent->AddChild(this);
00135         } else {
00136                 AddToWidgetList();
00137         }
00138         //_mid->rectClip = *this;
00139 }
00140 
00141 void PG_Widget::RemoveAllChilds() {
00142 
00143         // remove all child widgets
00144         if(_mid->childList != NULL) {
00145 
00146                 PG_Widget* i = _mid->childList->first();
00147                 while(i != NULL) {
00148                         PG_Widget* w = i;
00149                         i = i->next();
00150 
00151                         RemoveChild(w);
00152                         delete w;
00153                 }
00154                 _mid->childList->clear();
00155         }
00156 
00157 }
00158 
00159 PG_Widget::~PG_Widget() {
00160 
00161         _mid->inDestruct = true;
00162 
00163         if(!_mid->havesurface && my_srfObject) {
00164                 PG_LogWRN("DrawObject declared without a surface has unexpectedly born one ?");
00165         }
00166         PG_Application::UnloadSurface(my_srfObject);
00167         my_srfObject = NULL;
00168 
00169         Hide();
00170 
00171         RemoveAllChilds();
00172 
00173         // remove myself from my parent's childlist (if any parent)
00174 
00175         if (GetParent() != NULL) {
00176                 GetParent()->RemoveChild(this);
00177         } else {
00178                 RemoveFromWidgetList();
00179         }
00180 
00181         // remove childlist
00182         delete _mid->childList;
00183         _mid->childList = NULL;
00184 
00185         if (_mid->userdata != NULL) {
00186                 delete[] _mid->userdata;
00187         }
00188 
00189         // remove the font
00190         delete _mid->font;
00191 
00192         // remove my private data
00193         delete _mid;
00194 
00195         //cout << "Removed widget '" << GetName() << "'" << endl;
00196 }
00197 
00198 void PG_Widget::RemoveFromWidgetList() {
00199         widgetList.Remove(this);
00200 }
00201 
00202 void PG_Widget::AddToWidgetList() {
00203         if(!GetParent()) {
00204                 widgetList.Add(this);
00205         }
00206 }
00207 
00210 bool PG_Widget::AcceptEvent(const SDL_Event * event) {
00211 
00212         if (!IsVisible() || IsHidden()) {
00213                 return false;
00214         }
00215 
00216         switch (event->type) {
00217                 case SDL_MOUSEMOTION:
00218                         if ((event->motion.x < _mid->rectClip.my_xpos) ||
00219                                 (event->motion.x > (_mid->rectClip.my_xpos + _mid->rectClip.my_width - 1))) {
00220                                 if (_mid->mouseInside) {
00221                                         eventMouseLeave();
00222                                 }
00223                                 return false;
00224                         }
00225                         if ((event->motion.y < _mid->rectClip.my_ypos) ||
00226                                 (event->motion.y > (_mid->rectClip.my_ypos + _mid->rectClip.my_height - 1))) {
00227                                 if (_mid->mouseInside) {
00228                                         eventMouseLeave();
00229                                 }
00230                                 return false;
00231                         }
00232                         if (!_mid->mouseInside) {
00233                                 _mid->mouseInside = true;
00234                                 eventMouseEnter();
00235                                 return true;
00236                         }
00237                         break;
00238 
00239                 case SDL_MOUSEBUTTONUP:
00240                 case SDL_MOUSEBUTTONDOWN:
00241                         if ((event->button.x < _mid->rectClip.my_xpos) ||
00242                                 (event->button.x > (_mid->rectClip.my_xpos + _mid->rectClip.my_width - 1)))
00243                                 return false;
00244 
00245                         if ((event->button.y < _mid->rectClip.my_ypos) ||
00246                                 (event->button.y > (_mid->rectClip.my_ypos + _mid->rectClip.my_height - 1)))
00247                                 return false;
00248 
00249                         break;
00250         }
00251 
00252         return true;            // accept the event as default
00253 }
00254 
00255 
00257 void PG_Widget::eventMouseEnter() {
00258         sigMouseEnter();
00259 }
00260 
00261 
00263 void PG_Widget::eventMouseLeave() {
00264         _mid->mouseInside = false;
00265 
00266         if(GetParent() != NULL && !GetParent()->IsMouseInside()) {
00267                 GetParent()->eventMouseLeave();
00268         }
00269 
00270         sigMouseLeave();
00271         /*if(GetParent()) {
00272                 GetParent()->eventMouseLeave();
00273         }*/
00274 }
00275 
00277 void PG_Widget::eventShow() {}
00278 
00280 void PG_Widget::eventHide() {}
00281 
00283 PG_Point PG_Widget::ClientToScreen(int sx, int sy) {
00284         return PG_Point(sx + my_xpos, sy + my_ypos);
00285 }
00286 
00287 PG_Point PG_Widget::ScreenToClient(int x, int y) {
00288         return PG_Point(x - my_xpos, y - my_ypos);
00289 }
00290 
00291 void PG_Widget::AddChild(PG_Widget * child) {
00292 
00293         if (!child)
00294                 return;
00295 
00296         // remove our new child from previous lists
00297         if(child->GetParent()) {
00298                 child->GetParent()->RemoveChild(child);
00299         } else {
00300                 child->RemoveFromWidgetList();
00301         }
00302 
00303         child->MoveRect(child->my_xpos + my_xpos, child->my_ypos + my_ypos);
00304         child->_mid->widgetParent = this;
00305 
00306         if (_mid->childList == NULL) {
00307                 _mid->childList = new PG_RectList;
00308         }
00309 
00310         _mid->childList->Add(child);
00311 }
00312 
00313 bool PG_Widget::MoveWidget(int x, int y, bool update) {
00314         SDL_Surface* screen = PG_Application::GetScreen();
00315 
00316         if (GetParent() != NULL) {
00317                 x += GetParent()->my_xpos;
00318                 y += GetParent()->my_ypos;
00319         }
00320         if(x == my_xpos && y == my_ypos) {
00321                 // Optimization: We haven't moved, so do nothing.
00322                 return false;
00323         }
00324 
00325         if(!IsVisible() || IsHidden() || !update) {
00326                 MoveRect(x, y);
00327                 return true;
00328         }
00329 
00330         // delta x,y
00331         int dx = x - my_xpos;
00332         int dy = y - my_ypos;
00333 
00334         // calculate vertical update rect
00335 
00336         PG_Rect vertical(0, 0, abs(dx), my_height + abs(dy));
00337 
00338         if(dx >= 0) {
00339                 vertical.my_xpos = my_xpos;
00340         } else {
00341                 vertical.my_xpos = my_xpos + my_width + dx;
00342         }
00343 
00344         vertical.my_ypos = my_ypos;
00345 
00346         // calculate vertical update rect
00347 
00348         PG_Rect horizontal(0, 0, my_width + abs(dx), abs(dy));
00349 
00350         horizontal.my_xpos = my_xpos;
00351 
00352         if(dy >= 0) {
00353                 horizontal.my_ypos = my_ypos;
00354         } else {
00355                 horizontal.my_ypos = my_ypos + my_height + dy;
00356         }
00357 
00358         // move rectangle and store new background
00359         MoveRect(x, y);
00360 
00361         if(vertical.my_xpos + vertical.my_width > screen->w) {
00362                 vertical.my_width = screen->w - vertical.my_xpos;
00363         }
00364         if(vertical.my_ypos + vertical.my_height > screen->h) {
00365                 vertical.my_height = screen->h - vertical.my_ypos;
00366         }
00367 
00368         if(horizontal.my_xpos + horizontal.my_width > screen->w) {
00369                 horizontal.my_width = screen->w- horizontal.my_xpos;
00370         }
00371         if(horizontal.my_ypos + horizontal.my_height > screen->h) {
00372                 horizontal.my_height = screen->h - horizontal.my_ypos;
00373         }
00374 
00375         if(!PG_Application::GetBulkMode()) {
00376 
00377                 // I'm experimenting with cairo - this change was needed to
00378                 // make rendering work as expected -- Alex
00379 
00380                 /*UpdateRect(vertical);
00381                 UpdateRect(horizontal);
00382                 UpdateRect(_mid->rectClip);
00383                 PG_Application::LockScreen();
00384                 SDL_Rect rects[3] = {_mid->rectClip, vertical, horizontal};
00385                 PG_Application::UpdateRects(screen, 3, rects);
00386                 PG_Application::UnlockScreen();*/
00387 
00388                 int minx, maxx;
00389                 int miny, maxy;
00390                 minx = PG_MIN(vertical.x, horizontal.x);
00391                 minx = PG_MIN(minx, _mid->rectClip.x);
00392                 maxx = PG_MAX(vertical.x+vertical.w, horizontal.x+horizontal.w);
00393                 maxx = PG_MAX(maxx, _mid->rectClip.x+_mid->rectClip.w);
00394 
00395                 miny = PG_MIN(vertical.y, horizontal.y);
00396                 miny = PG_MIN(miny, _mid->rectClip.y);
00397                 maxy = PG_MAX(vertical.y+vertical.h, horizontal.y+horizontal.h);
00398                 maxy = PG_MAX(maxy, _mid->rectClip.y+_mid->rectClip.h);
00399 
00400            PG_Application::ScreenLocker locker(true);
00401                 PG_Rect rect(minx,miny,maxx-minx,maxy-miny);
00402                 UpdateRect(rect);
00403                 PG_Application::UpdateRects(screen, 1, &rect);
00404         }
00405 
00406         return true;
00407 }
00408 
00409 bool PG_Widget::MoveWidget(const PG_Rect& r, bool update) {
00410         SizeWidget(r.w, r.h, update);
00411         MoveWidget(r.x, r.y, update);
00412 
00413         return true;
00414 }
00415 
00416 bool PG_Widget::SizeWidget(Uint16 w, Uint16 h, bool update) {
00417         Uint16 old_w = my_width;
00418         Uint16 old_h = my_height;
00419 
00420         if(my_width == w && my_height == h) {
00421                 return false;
00422         }
00423 
00424         // create new widget drawsurface
00425         if(my_srfObject) {
00426                 PG_Application::UnloadSurface(my_srfObject);
00427 
00428                 if(w > 0 && h > 0) {
00429                         my_srfObject = PG_Draw::CreateRGBSurface(w, h);
00430                 } else {
00431                         my_srfObject = NULL;
00432                 }
00433         }
00434 
00435         eventSizeWidget(w, h);
00436 
00437         my_width = w;
00438         my_height = h;
00439 
00440         if(!IsVisible() || IsHidden() || !update) {
00441                 return true;
00442         }
00443 
00444         if(my_srfObject) {
00445                 Redraw();
00446         } else {
00447                 if(old_w > w || old_h > h) {
00448                         PG_Rect u(
00449                             my_xpos,
00450                             my_ypos,
00451                             (old_w > w) ? old_w : w,
00452                             (old_h > h) ? old_h : h);
00453 
00454                         // Fix: If you decrease the resolution of your application,
00455                         // you must decrease the window sizes as well. However, this
00456                         // code will create an out of bounds X error since x + old_w
00457                         // (or y + old_h) are now out of range.
00458                         if (my_xpos + old_w >= PG_Application::GetScreenWidth())
00459                                 u.my_width = PG_Application::GetScreenWidth() - my_xpos;
00460 
00461                         if (my_ypos + old_h >= PG_Application::GetScreenHeight())
00462                                 u.my_height = PG_Application::GetScreenHeight() - my_ypos;
00463 
00464                         UpdateRect(u);
00465                         PG_Application::UpdateRects(PG_Application::GetScreen(), 1, &u);
00466                 } else {
00467                         Update();
00468                 }
00469         }
00470 
00471         return true;
00472 }
00473 
00475 bool PG_Widget::ProcessEvent(const SDL_Event * event, bool bModal) {
00476 
00477         bool processed = false;
00478         // do i have a capturehook set ? (modal)
00479         if(bModal) {
00480                 // i will send that event to my children
00481 
00482                 if(_mid->childList != NULL) {
00483                         PG_Widget* list = _mid->childList->first();
00484 
00485                         while (!processed && (list != NULL)) {
00486                                 processed = list->ProcessEvent(event, true);
00487                                 list = list->next();
00488                         }
00489                 }
00490 
00491                 if(processed) {
00492                         return processed;
00493                 }
00494         }
00495 
00496         // let me see if i can process it myself
00497 
00498         if(PG_MessageObject::ProcessEvent(event)) {
00499                 return true;
00500         }
00501 
00502         if(bModal) {
00503                 return processed;
00504         }
00505 
00506         // ask my parent to process the event
00507 
00508         if(GetParent()) {
00509                 if(GetParent()->ProcessEvent(event)) {
00510                         return true;
00511                 }
00512         }
00513 
00514         return false;
00515 }
00516 
00517 bool PG_Widget::RemoveChild(PG_Widget * child) {
00518         if(_mid->childList == NULL || child == NULL) {
00519                 return false;
00520         }
00521 
00522         if(_mid->childList->Remove(child)) {
00523                 child->MoveRect(child->my_xpos - my_xpos, child->my_ypos - my_ypos);
00524                 return true;
00525         }
00526 
00527         return false;
00528 }
00529 
00530 bool PG_Widget::IsMouseInside() {
00531         int x, y;
00532         PG_Application::GetEventSupplier()->GetMouseState(x, y);
00533         PG_Point p(x, y);
00534         _mid->mouseInside = IsInside(p);
00535 
00536         return _mid->mouseInside;
00537 }
00538 
00540 bool PG_Widget::Redraw(bool update) {
00541         PG_Rect r(0, 0, my_width, my_height);
00542 
00543         if(my_srfObject != NULL) {
00544                 eventDraw(my_srfObject, r);
00545         }
00546 
00547         if(_mid->childList != NULL) {
00548                 for(PG_Widget* i = _mid->childList->first(); i != NULL; i = i->next()) {
00549                         i->Redraw(false);
00550                 }
00551         }
00552 
00553         if (update) {
00554                 Update();
00555         }
00556         return true;
00557 }
00558 
00559 void PG_Widget::SetVisible(bool visible) {
00560 
00561         if(IsHidden()) {
00562                 return;
00563         }
00564 
00565         // Attempt to make object visible
00566         if(visible) {
00567                 if(_mid->visible) {                     // Object already visible
00568                         return;
00569                 } else {                                        // Display object
00570                         _mid->visible = visible;
00571                         if(_mid->firstredraw) {
00572                                 Redraw(false);
00573                                 _mid->firstredraw = false;
00574                         }
00575                 }
00576 
00577         }
00578 
00579         // Attempt to make object invisible
00580         if(!visible) {
00581                 if(!_mid->visible) {                    // Object is already invisible
00582                         return;
00583                 } else {                                        // Hide object
00584                         //RestoreBackground();
00585                         _mid->visible = visible;
00586                 }
00587         }
00588 
00589         if(_mid->childList != NULL) {
00590                 for(PG_Widget* i = _mid->childList->first(); i != NULL; i = i->next()) {
00591                         i->SetVisible(visible);
00592                         if(!i->IsHidden()) {
00593                                 if(visible) {
00594                                         i->eventShow();
00595                                 } else {
00596                                         i->eventHide();
00597                                 }
00598                         }
00599                 }
00600         }
00601 }
00602 
00604 void PG_Widget::Show(bool fade) {
00605 
00606         if(fade && IsVisible() && !IsHidden()) {
00607                 fade = false;
00608         }
00609 
00610         PG_Widget* parent = GetParent();
00611         if(parent == NULL) {
00612                 widgetList.BringToFront(this);
00613         } else {
00614                 parent->GetChildList()->BringToFront(this);
00615         }
00616 
00617         SetHidden(false);
00618 
00619         if(parent != NULL && (!parent->IsVisible() || parent->IsHidden())) {
00620                 return;
00621         }
00622 
00623         SetVisible(true);
00624         eventShow();
00625 
00626         if (fade) {
00627                 FadeIn();
00628         }
00629 
00630         if(IsMouseInside()) {
00631                 eventMouseEnter();
00632         }
00633 
00634         //SDL_SetClipRect(my_srfScreen, NULL);
00635         Update();
00636 
00637         return;
00638 }
00639 
00641 void PG_Widget::Hide(bool fade) {
00642         SDL_Surface* screen = PG_Application::GetScreen();
00643 
00644         if(!IsVisible()) {
00645                 SetHidden(true);
00646                 eventHide();
00647                 return;
00648         }
00649 
00650         RecalcClipRect();
00651 
00652         if(!_mid->inDestruct && !_mid->inMouseLeave) {
00653                 _mid->inMouseLeave = true;
00654                 eventMouseLeave();
00655                 _mid->inMouseLeave = false;
00656         }
00657 
00658         if (fade) {
00659                 FadeOut();
00660         }
00661 
00662         SetVisible(false);
00663         eventHide();
00664 
00665         ReleaseCapture();
00666         ReleaseInputFocus();
00667 
00668         SDL_SetClipRect(screen, NULL);
00669 
00670         if(!PG_Application::GetBulkMode()) {
00671                 UpdateRect(_mid->rectClip);
00672 
00673            PG_Application::ScreenLocker locker(true);
00674                 PG_Application::UpdateRects(screen, 1, &_mid->rectClip);
00675         }
00676 
00677         SetHidden(true);
00678 
00679         return;
00680 }
00681 
00683 void PG_Widget::MoveRect(int x, int y) {
00684         int dx = x - my_xpos;
00685         int dy = y - my_ypos;
00686 
00687         my_xpos = x;
00688         my_ypos = y;
00689         _mid->rectClip.my_xpos += dx;
00690         _mid->rectClip.my_ypos += dy;
00691 
00692         // recalc cliprect
00693         RecalcClipRect();
00694 
00695         if(_mid->childList != NULL) {
00696                 for(PG_Widget* i = _mid->childList->first(); i != NULL; i = i->next()) {
00697                         i->MoveRect(i->my_xpos + dx, i->my_ypos + dy);
00698                 }
00699         }
00700 
00701         eventMoveWidget(x, y);
00702 }
00703 
00704 void PG_Widget::Blit(bool recursive, bool restore) {
00705 
00706         if(!_mid->visible || _mid->hidden) {
00707                 return;
00708         }
00709 
00710         // recalc clipping rectangle
00711         RecalcClipRect();
00712 
00713         // don't draw a null rect
00714         if(_mid->rectClip.w == 0 || _mid->rectClip.h == 0) {
00715                 return;
00716         }
00717 
00718         PG_Rect src;
00719         PG_Rect dst;
00720    PG_Application::ScreenLocker locker(true);
00721 
00722         // restore the background
00723         if(restore) {
00724                 RestoreBackground(&_mid->rectClip);
00725         }
00726 
00727         // get source & destination rectangles
00728         src.SetRect(_mid->rectClip.x - my_xpos, _mid->rectClip.y - my_ypos, _mid->rectClip.w, _mid->rectClip.h);
00729         dst = _mid->rectClip;
00730 
00731         // call the blit handler
00732         eventBlit(my_srfObject, src, dst);
00733 
00734         // should we draw our children
00735         if(recursive) {
00736                 // draw the children-list
00737                 if(_mid->childList != NULL) {
00738                         _mid->childList->Blit(_mid->rectClip);
00739                 }
00740         }
00741 }
00742 
00744 void PG_Widget::Update(bool doBlit) {
00745         static PG_Rect src;
00746         static PG_Rect dst;
00747 
00748         if(PG_Application::GetBulkMode()) {
00749                 return;
00750         }
00751 
00752         if(!_mid->visible || _mid->hidden) {
00753                 return;
00754         }
00755 
00756         // recalc cliprect
00757         RecalcClipRect();
00758 
00759         if(_mid->rectClip.w == 0 || _mid->rectClip.h == 0) {
00760                 return;
00761         }
00762 
00763    PG_Application::ScreenLocker locker(true);
00764 
00765         // BLIT
00766         if(doBlit) {
00767 
00768                 SDL_SetClipRect(PG_Application::GetScreen(), &_mid->rectClip);
00769                 RestoreBackground(&_mid->rectClip);
00770 
00771                 src.SetRect(_mid->rectClip.x - my_xpos, _mid->rectClip.y - my_ypos, _mid->rectClip.w, _mid->rectClip.h);
00772                 dst = _mid->rectClip;
00773 
00774                 if(GetParent() != NULL && _mid->updateOverlappingSiblings )
00775                         if( !_mid->dirtyUpdate || (_mid->transparency > 0) ) {
00776                                 PG_RectList* children = GetParent()->GetChildList();
00777                                 if(children) {
00778                                         children->Blit(_mid->rectClip, GetParent()->GetChildList()->first(), this);
00779                                 }
00780                         }
00781 
00782                 eventBlit(my_srfObject, src, dst);
00783 
00784                 if(_mid->childList != NULL) {
00785                         _mid->childList->Blit(_mid->rectClip);
00786                 }
00787 
00788                 if(GetParent() != NULL && _mid->updateOverlappingSiblings ) {
00789                         PG_RectList* children = GetParent()->GetChildList();
00790                         if(children) {
00791                                 children->Blit(_mid->rectClip, this->next() );
00792                         }
00793                 }
00794 
00795                 // find the toplevel widget
00796                 PG_Widget* obj = GetToplevelWidget();
00797                 widgetList.Blit(_mid->rectClip, obj->next());
00798 
00799         }
00800 
00801         // Update screen surface
00802 #ifdef DEBUG
00803         PG_LogDBG("UPD: x:%d y:%d w:%d h:%d",dst.x,dst.y,dst.w,dst.h);
00804 #endif // DEBUG
00805 
00806         PG_Application::UpdateRects(PG_Application::GetScreen(), 1, &_mid->rectClip);
00807 
00808         SDL_SetClipRect(PG_Application::GetScreen(), NULL);
00809 }
00810 
00812 void PG_Widget::SetChildTransparency(Uint8 t) {
00813         if(_mid->childList == NULL) {
00814                 return;
00815         }
00816 
00817         for(PG_Widget* i = _mid->childList->first(); i != NULL; i = i->next()) {
00818                 i->SetTransparency(t, true);
00819         }
00820         Update();
00821 }
00822 
00823 void PG_Widget::StartWidgetDrag() {
00824         int x, y;
00825 
00826         PG_Application::GetEventSupplier()->GetMouseState(x, y);
00827         _mid->ptDragStart.x = static_cast<Sint16>(x) - my_xpos;
00828         _mid->ptDragStart.y = static_cast<Sint16>(y) - my_ypos;
00829 }
00830 
00831 void PG_Widget::WidgetDrag(int x, int y) {
00832 
00833         x -= _mid->ptDragStart.x;
00834         y -= _mid->ptDragStart.y;
00835 
00836         if(x < 0)
00837                 x=0;
00838         if(y < 0)
00839                 y=0;
00840         if(x > (PG_Application::GetScreenWidth() - my_width -1))
00841                 x = (PG_Application::GetScreenWidth() - my_width -1);
00842         if(y > (PG_Application::GetScreenHeight() - my_height -1))
00843                 y = (PG_Application::GetScreenHeight() - my_height -1);
00844 
00845         MoveWidget(x,y);
00846 }
00847 
00848 void PG_Widget::EndWidgetDrag(int x, int y) {
00849         WidgetDrag(x,y);
00850         _mid->ptDragStart.x = 0;
00851         _mid->ptDragStart.y = 0;
00852 }
00853 
00854 void PG_Widget::HideAll() {
00855         for(PG_Widget* i = widgetList.first(); i != NULL; i = i->next()) {
00856                 i->Hide();
00857         }
00858 }
00859 
00860 /*void PG_Widget::BulkUpdate() {
00861         bBulkUpdate = true;
00862  
00863         for(PG_Widget* i = widgetList.first(); i != NULL; i = i->next()) {
00864                 if(i->IsVisible()) {
00865                         i->Update();
00866                 }
00867         }
00868  
00869         bBulkUpdate = false;
00870 }*/
00871 
00872 void PG_Widget::BulkBlit() {
00873         //bBulkUpdate = true;
00874         widgetList.Blit();
00875         PG_Application::DrawCursor();
00876         //bBulkUpdate = false;
00877 }
00878 
00879 void PG_Widget::LoadThemeStyle(const std::string& widgettype, const std::string& objectname) {
00880         PG_Theme* t = PG_Application::GetTheme();
00881         PG_Color c;
00882 
00883         const std::string& font = t->FindFontName(widgettype, objectname);
00884         int fontsize = t->FindFontSize(widgettype, objectname);
00885         PG_Font::Style fontstyle = t->FindFontStyle(widgettype, objectname);
00886 
00887         if(!font.empty()) {
00888                 SetFontName(font, true);
00889         }
00890 
00891         if (fontsize > 0)
00892                 SetFontSize(fontsize, true);
00893 
00894         if (fontstyle >= 0)
00895                 SetFontStyle(fontstyle, true);
00896 
00897         c = GetFontColor();
00898         t->GetColor(widgettype, objectname, PG_PropStr::textcolor, c);
00899         SetFontColor(c);
00900 
00901    c = GetFontHighlightColor();
00902    t->GetColor(widgettype, objectname, PG_PropStr::texthighlightcolor, c);
00903    SetFontHighlightColor(c);
00904 
00905    
00906         t->GetColor(widgettype, objectname, PG_PropStr::bordercolor0, my_colorBorder[0][0]);
00907         t->GetColor(widgettype, objectname, PG_PropStr::bordercolor1, my_colorBorder[1][0]);
00908         t->GetColor(widgettype, objectname, PG_PropStr::bordercolor0i, my_colorBorder[0][1]);
00909         t->GetColor(widgettype, objectname, PG_PropStr::bordercolor1i, my_colorBorder[1][1]);
00910 }
00911 
00912 void PG_Widget::LoadThemeStyle(const std::string& widgettype) {}
00913 
00914 void PG_Widget::FadeOut() {
00915         PG_Rect r(0, 0, my_width, my_height);
00916 
00917         // blit the widget to screen (invisible)
00918         Blit();
00919 
00920         // create a temp surface
00921         SDL_Surface* srfFade = PG_Draw::CreateRGBSurface(my_width, my_height);
00922         SDL_Surface* screen = PG_Application::GetScreen();
00923 
00924         int d = (255-_mid->transparency)/ _mid->fadeSteps;
00925         if(!d) {
00926                 d = 1;
00927         } // minimum step == 1
00928 
00929    PG_Application::ScreenLocker locker(true);
00930 
00931         // blit the widget to temp surface
00932         PG_Draw::BlitSurface(screen, *this, srfFade, r);
00933 
00934         for(int i=_mid->transparency; i<255; i += d) {
00935                 RestoreBackground(NULL, true);
00936                 SDL_SetAlpha(srfFade, SDL_SRCALPHA, 255-i);
00937                 SDL_BlitSurface(srfFade, NULL, screen, this);
00938                 PG_Application::UpdateRects(screen, 1, &_mid->rectClip);
00939         }
00940 
00941         RestoreBackground(NULL, true);
00942         SDL_SetAlpha(srfFade, SDL_SRCALPHA, 0);
00943         SDL_BlitSurface(srfFade, NULL, screen, this);
00944         SetVisible(false);
00945         locker.unlock();
00946 
00947         Update(false);
00948 
00949         PG_Application::UnloadSurface(srfFade);
00950 }
00951 
00952 void PG_Widget::FadeIn() {
00953         SDL_Surface* screen = PG_Application::GetScreen();
00954 
00955         // blit the widget to screen (invisible)
00956         SDL_SetClipRect(screen, NULL);
00957         Blit();
00958 
00959         PG_Rect src(
00960             0,
00961             0,
00962             (my_xpos < 0) ? my_width + my_xpos : my_width,
00963             (my_ypos < 0) ? my_height + my_ypos : my_height);
00964 
00965         // create a temp surface
00966         SDL_Surface* srfFade = PG_Draw::CreateRGBSurface(w, h);
00967 
00968    PG_Application::ScreenLocker locker(true);
00969 
00970         // blit the widget to temp surface
00971         PG_Draw::BlitSurface(screen, _mid->rectClip, srfFade, src);
00972 
00973         int d = (255-_mid->transparency)/ _mid->fadeSteps;
00974 
00975         if(!d) {
00976                 d = 1;
00977         } // minimum step == 1
00978         for(int i=255; i>_mid->transparency; i -= d) {
00979                 RestoreBackground(NULL, true);
00980                 SDL_SetAlpha(srfFade, SDL_SRCALPHA, 255-i);
00981                 PG_Draw::BlitSurface(srfFade, src, screen, _mid->rectClip);
00982                 PG_Application::UpdateRects(screen, 1, &_mid->rectClip);
00983         }
00984 
00985         locker.unlock();
00986 
00987         Update();
00988 
00989         PG_Application::UnloadSurface(srfFade);
00990 }
00991 
00992 void PG_Widget::SetFadeSteps(int steps) {
00993         _mid->fadeSteps = steps;
00994 }
00995 
00996 bool PG_Widget::Action(KeyAction action) {
00997         int x = my_xpos + my_width / 2;
00998         int y = my_ypos + my_height / 2;
00999 
01000         switch(action) {
01001                 case ACT_ACTIVATE:
01002                         SDL_WarpMouse(x,y);
01003                         eventMouseEnter();
01004                         break;
01005 
01006                 case ACT_DEACTIVATE:
01007                         eventMouseLeave();
01008                         break;
01009 
01010                 case ACT_OK:
01011                         SDL_MouseButtonEvent button;
01012                         button.button = 1;
01013                         button.x = x;
01014                         button.y = y;
01015                         eventMouseButtonDown(&button);
01016                         SDL_Delay(200);
01017                         eventMouseButtonUp(&button);
01018                         Action(ACT_ACTIVATE);
01019                         break;
01020 
01021                 default:
01022                         break;
01023         }
01024 
01025         return false;
01026 }
01027 
01028 bool PG_Widget::RestoreBackground(PG_Rect* clip, bool force) {
01029 
01030         if(_mid->dirtyUpdate && (_mid->transparency == 0) && !force) {
01031                 return false;
01032         }
01033 
01034         if(PG_Application::GetBulkMode()) {
01035                 return false;
01036         }
01037 
01038         if(clip == NULL) {
01039                 clip = &_mid->rectClip;
01040         }
01041 
01042         if(GetParent() == NULL) {
01043                 PG_Application::RedrawBackground(*clip);
01044 
01045                 if(widgetList.first() != this) {
01046                         SDL_SetClipRect(PG_Application::GetScreen(), clip);
01047                         widgetList.Blit(*clip, widgetList.first(), this);
01048                         SDL_SetClipRect(PG_Application::GetScreen(), NULL);
01049                 }
01050                 return true;
01051         }
01052 
01053         GetParent()->RestoreBackground(clip);
01054         SDL_SetClipRect(PG_Application::GetScreen(), clip);
01055         GetParent()->Blit(false, false);
01056         SDL_SetClipRect(PG_Application::GetScreen(), NULL);
01057 
01058         return true;
01059 }
01060 
01061 PG_Widget* PG_Widget::FindWidgetFromPos(int x, int y) {
01062         PG_Point p;
01063         p.x = x;
01064         p.y = y;
01065         bool finished = false;
01066 
01067         PG_Widget* toplevel = widgetList.IsInside(p);
01068         PG_Widget* child = NULL;
01069 
01070         if(!toplevel) {
01071                 return NULL;
01072         }
01073 
01074         while(!finished) {
01075 
01076                 if(toplevel->GetChildList()) {
01077                         child = toplevel->GetChildList()->IsInside(p);
01078 
01079                         if(child) {
01080                                 toplevel = child;
01081                                 child = NULL;
01082                         } else {
01083                                 finished = true;
01084                         }
01085 
01086                 } else {
01087                         finished = true;
01088                 }
01089         }
01090 
01091         return toplevel;
01092 }
01093 
01094 void PG_Widget::UpdateRect(const PG_Rect& r) {
01095         if(PG_Application::GetBulkMode()) {
01096                 return;
01097         }
01098 
01099         SDL_Surface* screen = PG_Application::GetScreen();
01100 
01101    PG_Application::ScreenLocker locker(true);
01102         PG_Application::RedrawBackground(r);
01103         SDL_SetClipRect(screen, (PG_Rect*)&r);
01104         widgetList.Blit(r);
01105         SDL_SetClipRect(screen, NULL);
01106 }
01107 
01108 void PG_Widget::UpdateScreen() {
01109         UpdateRect( PG_Rect(0, 0, PG_Application::GetScreenWidth(), PG_Application::GetScreenHeight()) );
01110    PG_Application::UpdateRect( PG_Application::GetScreen(), 0, 0, 0, 0 );
01111 }
01112 
01113 bool PG_Widget::IsInFrontOf(PG_Widget* widget) {
01114         PG_Widget* w1 = NULL;
01115         PG_Widget* w2 = NULL;
01116         PG_RectList* list = &widgetList;
01117 
01118         // do both widgets have the same parent ?
01119         if((GetParent() != NULL) && (GetParent() == widget->GetParent())) {
01120                 w1 = this;
01121                 w2 = widget;
01122                 list = GetParent()->GetChildList();
01123         } else {
01124                 w1 = this->GetToplevelWidget();
01125                 w2 = widget->GetToplevelWidget();
01126         }
01127 
01128         return (w1->index > w2->index);
01129 }
01130 
01131 PG_Widget* PG_Widget::GetToplevelWidget() {
01132         if(GetParent() == NULL) {
01133                 return this;
01134         }
01135 
01136         return GetParent()->GetToplevelWidget();
01137 }
01138 
01139 void PG_Widget::SendToBack() {
01140         if(GetParent() == NULL) {
01141                 widgetList.SendToBack(this);
01142         } else {
01143                 GetParent()->GetChildList()->SendToBack(this);
01144         }
01145         Update();
01146 }
01147 
01148 void PG_Widget::BringToFront() {
01149         if(GetParent() == NULL) {
01150                 widgetList.BringToFront(this);
01151         } else {
01152                 GetParent()->GetChildList()->BringToFront(this);
01153         }
01154         Update();
01155 }
01156 
01157 void PG_Widget::RecalcClipRect() {
01158         PG_Rect pr;
01159 
01160         if (_mid->widgetParent != NULL) {
01161                 pr = *(_mid->widgetParent->GetClipRect());
01162         } else {
01163                 pr.SetRect(
01164                     0,
01165                     0,
01166                     PG_Application::GetScreenWidth(),
01167                     PG_Application::GetScreenHeight());
01168         }
01169 
01170         PG_Rect ir = IntersectRect(pr);
01171         SetClipRect(ir);
01172 }
01173 
01174 bool PG_Widget::LoadLayout(const std::string& name) {
01175         bool rc = PG_Layout::Load(this, name, NULL, NULL);
01176         Update();
01177         return rc;
01178 }
01179 
01180 bool PG_Widget::LoadLayout(const std::string& name, void (* WorkCallback)(int now, int max)) {
01181         bool rc = PG_Layout::Load(this, name, WorkCallback, NULL);
01182         Update();
01183         return rc;
01184 
01185 }
01186 
01187 bool PG_Widget::LoadLayout(const std::string& name, void (* WorkCallback)(int now, int max),void *UserSpace) {
01188         bool rc = PG_Layout::Load(this, name, WorkCallback, UserSpace);
01189         Update();
01190         return rc;
01191 }
01192 
01193 void PG_Widget::SetUserData(void *userdata, int size) {
01194         _mid->userdata = new char[size];
01195         memcpy(_mid->userdata, userdata, size);
01196         _mid->userdatasize = size;
01197 }
01198 
01199 int PG_Widget::GetUserDataSize() {
01200         return _mid->userdatasize;
01201 }
01202 
01203 void PG_Widget::GetUserData(void *userdata) {
01204         if (_mid->userdata == NULL)
01205                 return;
01206 
01207         memcpy(userdata, _mid->userdata, _mid->userdatasize);
01208 }
01209 
01210 void PG_Widget::ReleaseUserData() {
01211         if (_mid->userdata != NULL)
01212                 delete[] _mid->userdata;
01213         _mid->userdatasize = 0;
01214 }
01215 
01216 void PG_Widget::AddText(const std::string& text, bool update) {
01217         my_text += text;
01218         _mid->widthText = TXT_HEIGHT_UNDEF;
01219         _mid->heightText = TXT_HEIGHT_UNDEF;
01220 
01221         //TO-DO : Optimalize this !!! - because of widget functions overloading SetText()
01222         if (update) {
01223                 SetText(GetText());
01224         }
01225 }
01226 
01227 void PG_Widget::SetText(const std::string& text) {
01228 
01229         _mid->widthText = TXT_HEIGHT_UNDEF;
01230         _mid->heightText = TXT_HEIGHT_UNDEF;
01231 
01232         my_text = text;
01233         Update();
01234 }
01235 
01236 void PG_Widget::SetTextFormat(const char* text, ...) {
01237         va_list ap;
01238         va_start(ap, text);
01239         char temp[256];
01240 
01241         if(text == NULL) {
01242                 my_text = "";
01243                 return;
01244         }
01245 
01246         if(text[0] == 0) {
01247                 my_text = "";
01248                 return;
01249         }
01250 
01251         vsprintf(temp, text, ap);
01252         SetText(temp);
01253         va_end(ap);
01254 }
01255 
01256 void PG_Widget::SetFontColor(const PG_Color& Color, bool bRecursive) {
01257         _mid->font->SetColor(Color);
01258 
01259         if(!bRecursive || (GetChildList() == NULL)) {
01260                 return;
01261         }
01262 
01263         for(PG_Widget* i = GetChildList()->first(); i != NULL; i = i->next()) {
01264                 i->SetFontColor(Color, true);
01265         }
01266 }
01267 
01268 void PG_Widget::SetFontHighlightColor(const PG_Color& Color, bool bRecursive) {
01269    _mid->font->SetHighlightColor(Color);
01270 
01271    if(!bRecursive || (GetChildList() == NULL)) {
01272       return;
01273    }
01274 
01275    for(PG_Widget* i = GetChildList()->first(); i != NULL; i = i->next()) {
01276       i->SetFontHighlightColor(Color, true);
01277    }
01278 }
01279 
01280 
01281 void PG_Widget::SetFontAlpha(int Alpha, bool bRecursive) {
01282         _mid->font->SetAlpha(Alpha);
01283 
01284         if(!bRecursive || (GetChildList() == NULL)) {
01285                 return;
01286         }
01287 
01288         for(PG_Widget* i = GetChildList()->first(); i != NULL; i = i->next()) {
01289                 i->SetFontAlpha(Alpha, true);
01290         }
01291 }
01292 
01293 void PG_Widget::SetFontStyle(PG_Font::Style Style, bool bRecursive) {
01294         _mid->font->SetStyle(Style);
01295 
01296         if(!bRecursive || (GetChildList() == NULL)) {
01297                 return;
01298         }
01299 
01300         for(PG_Widget* i = GetChildList()->first(); i != NULL; i = i->next()) {
01301                 i->SetFontStyle(Style, true);
01302         }
01303 }
01304 
01305 int PG_Widget::GetFontSize() {
01306         return _mid->font->GetSize();
01307 }
01308 
01309 void PG_Widget::SetFontSize(int Size, bool bRecursive) {
01310         _mid->font->SetSize(Size);
01311 
01312         if(!bRecursive || (GetChildList() == NULL)) {
01313                 return;
01314         }
01315 
01316         for(PG_Widget* i = GetChildList()->first(); i != NULL; i = i->next()) {
01317                 i->SetFontSize(Size, true);
01318         }
01319 
01320 }
01321 
01322 void PG_Widget::SetFontIndex(int Index, bool bRecursive) {
01323         //      _mid->font->SetIndex(Index);
01324 }
01325 
01326 void PG_Widget::SetFontName(const std::string& Name, bool bRecursive) {
01327         _mid->font->SetName(Name);
01328 
01329         if(!bRecursive || (GetChildList() == NULL)) {
01330                 return;
01331         }
01332 
01333         for(PG_Widget* i = GetChildList()->first(); i != NULL; i = i->next()) {
01334                 i->SetFontName(Name, true);
01335         }
01336 
01337 }
01338 
01339 void PG_Widget::SetSizeByText(int Width, int Height, const std::string& Text) {
01340         Uint16 w,h;
01341         int baselineY;
01342 
01343         if (Text.empty()) {
01344                 if (!PG_FontEngine::GetTextSize(my_text, _mid->font, &w, &h, &baselineY)) {
01345                         return;
01346                 }
01347         } else {
01348                 PG_String ytext = Text;
01349                 if (!PG_FontEngine::GetTextSize(ytext, _mid->font, &w, &h, &baselineY)) {
01350                         return;
01351                 }
01352         }
01353 
01354         if (my_width == 0 && my_height > 0 && Width == 0) {
01355                 my_width = w;
01356                 my_ypos += (my_height - h - baselineY) >> 1;
01357                 my_height = h + baselineY;
01358         } else if (my_height == 0 && my_width > 0 && Height == 0) {
01359                 my_xpos += (my_width - w) >> 1;
01360                 my_width = w;
01361                 my_height = h + baselineY;
01362         } else {
01363                 my_width = w + Width;
01364                 my_height = h + Height + baselineY;
01365         }
01366 
01367 }
01368 
01369 void PG_Widget::SetFont(PG_Font* font) {
01370         if(_mid->font != NULL) {
01371                 delete _mid->font;
01372         }
01373 
01374         _mid->font = new PG_Font(font->GetName(), font->GetSize());
01375 }
01376 
01377 void PG_Widget::GetTextSize(Uint16& w, Uint16& h, const std::string& text) {
01378         if(text.empty()) {
01379                 if(_mid->widthText != TXT_HEIGHT_UNDEF) {
01380                         w = _mid->widthText;
01381                         h = _mid->heightText;
01382                         return;
01383                 }
01384                 GetTextSize(w, h, my_text, _mid->font);
01385                 _mid->widthText = w;
01386                 _mid->heightText = h;
01387                 return;
01388         }
01389 
01390         GetTextSize(w, h, text, _mid->font);
01391 }
01392 
01393 void PG_Widget::GetTextSize(Uint16& w, Uint16& h, const PG_String& text, PG_Font* font) {
01394    PG_Char c = PG_Application::GetHighlightingTag();
01395    if ( !c || text.find( c) == PG_String::npos )
01396       PG_FontEngine::GetTextSize(text, font, &w);
01397    else {
01398       PG_String t = text;
01399       PG_String::size_type pos = t.find( c);
01400       while ( pos != PG_String::npos )  {
01401          t.erase( pos, 1 );
01402          pos = t.find( c);
01403       }
01404       PG_FontEngine::GetTextSize(t, font, &w);
01405    }
01406       
0