00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "pgbutton.h"
00030 #include "pgapplication.h"
00031 #include "pgthemewidget.h"
00032 #include "pglog.h"
00033 #include "pgdraw.h"
00034 #include "pgtheme.h"
00035
00036 #include "propstrings_priv.h"
00037
00038 PG_Button::SignalButtonClick<> PG_Button::sigGlobalClick;
00039
00040 class PG_ButtonStateData {
00041 public:
00042 PG_ButtonStateData() : srf(NULL), srf_icon(NULL), bordersize(1), transparency(0),
00043 background(NULL), backMode(PG_Draw::TILE), backBlend(0) {}
00044 ;
00045
00046 SDL_Surface* srf;
00047 SDL_Surface* srf_icon;
00048 Uint8 bordersize;
00049 Uint8 transparency;
00050 PG_Gradient gradState;
00051 SDL_Surface* background;
00052 PG_Draw::BkMode backMode;
00053 int backBlend;
00054 };
00055
00056 class PG_ButtonDataInternal : public std::map<PG_Button::STATE, PG_ButtonStateData> {
00057 public:
00058
00059 PG_ButtonDataInternal() : free_icons(false), isPressed(false), togglemode(false), state(PG_Button::UNPRESSED), pressShift(1),
00060 iconindent(3), behaviour( PG_Button::SIGNALONRELEASE | PG_Button::MSGCAPTURE ) {}
00061 ;
00062
00063 bool free_icons;
00064 bool isPressed;
00065 bool togglemode;
00066 PG_Button::STATE state;
00067 int pressShift;
00068 Uint16 iconindent;
00069 int behaviour;
00070 };
00071
00072 PG_Button::PG_Button(PG_Widget* parent, const PG_Rect& r, const std::string& text, int id, const std::string& style) : PG_Widget(parent, r) {
00073 SetDirtyUpdate(false);
00074
00075 _mid = new PG_ButtonDataInternal;
00076
00077 SetText(text);
00078 SetID(id);
00079
00080 LoadThemeStyle(style);
00081 }
00082
00083 PG_Button::~PG_Button() {
00084 FreeSurfaces();
00085 FreeIcons();
00086
00087 delete _mid;
00088 }
00089
00090 void PG_Button::LoadThemeStyle(const std::string& widgettype) {
00091 LoadThemeStyle(PG_PropStr::Button, PG_PropStr::Button);
00092 if(widgettype != PG_PropStr::Button) {
00093 LoadThemeStyle(widgettype, PG_PropStr::Button);
00094 }
00095 }
00096
00097 void PG_Button::LoadThemeStyle(const std::string& widgettype, const std::string& objectname) {
00098 PG_Theme* t = PG_Application::GetTheme();
00099
00100 PG_Color fontcolor = GetFontColor();
00101 t->GetColor(widgettype, objectname, PG_PropStr::textcolor, fontcolor);
00102 SetFontColor(fontcolor);
00103
00104 switch (GetID()) {
00105 case OK:
00106 SetIcon(t->FindSurface(widgettype, objectname, "ok_icon"));
00107 break;
00108
00109 case YES:
00110 SetIcon(t->FindSurface(widgettype, objectname, "yes_icon"));
00111 break;
00112
00113 case NO:
00114 SetIcon(t->FindSurface(widgettype, objectname, "no_icon"));
00115 break;
00116
00117 case APPLY:
00118 SetIcon(t->FindSurface(widgettype, objectname, "apply_icon"));
00119 break;
00120
00121 case CANCEL:
00122 SetIcon(t->FindSurface(widgettype, objectname, "cancel_icon"));
00123 break;
00124
00125 case CLOSE:
00126 SetIcon(t->FindSurface(widgettype, objectname, "close_icon"));
00127 break;
00128
00129 case HELP:
00130 SetIcon(t->FindSurface(widgettype, objectname, "help_icon"));
00131 break;
00132
00133 default:
00134 SetIcon(
00135 t->FindSurface(widgettype, objectname, PG_PropStr::iconup),
00136 t->FindSurface(widgettype, objectname, PG_PropStr::icondown),
00137 t->FindSurface(widgettype, objectname, PG_PropStr::iconover)
00138 );
00139 break;
00140 }
00141
00142 PG_Gradient* g;
00143 g = t->FindGradient(widgettype, objectname, PG_PropStr::gradient0);
00144 if(g) {
00145 (*_mid)[UNPRESSED].gradState = *g;
00146 }
00147
00148 g = t->FindGradient(widgettype, objectname, PG_PropStr::gradient1);
00149 if(g) {
00150 (*_mid)[HIGHLITED].gradState = *g;
00151 }
00152
00153 g = t->FindGradient(widgettype, objectname, PG_PropStr::gradient2);
00154 if(g) {
00155 (*_mid)[PRESSED].gradState = *g;
00156 }
00157
00158 SDL_Surface* background;
00159 background = t->FindSurface(widgettype, objectname, PG_PropStr::background0);
00160 t->GetProperty(widgettype, objectname, PG_PropStr::backmode0, (*_mid)[UNPRESSED].backMode);
00161 SetBackground(UNPRESSED, background, (*_mid)[UNPRESSED].backMode);
00162
00163 background = t->FindSurface(widgettype, objectname, PG_PropStr::background1);
00164 t->GetProperty(widgettype, objectname, PG_PropStr::backmode1, (*_mid)[PRESSED].backMode);
00165 SetBackground(PRESSED, background, (*_mid)[PRESSED].backMode);
00166
00167 background = t->FindSurface(widgettype, objectname, PG_PropStr::background2);
00168 t->GetProperty(widgettype, objectname, PG_PropStr::backmode2, (*_mid)[HIGHLITED].backMode);
00169 SetBackground(HIGHLITED, background, (*_mid)[HIGHLITED].backMode);
00170
00171 t->GetProperty(widgettype, objectname, PG_PropStr::blend0, (*_mid)[UNPRESSED].backBlend);
00172 t->GetProperty(widgettype, objectname, PG_PropStr::blend1, (*_mid)[PRESSED].backBlend);
00173 t->GetProperty(widgettype, objectname, PG_PropStr::blend2, (*_mid)[HIGHLITED].backBlend);
00174
00175 t->GetProperty(widgettype, objectname, PG_PropStr::shift, _mid->pressShift);
00176
00177 t->GetProperty(widgettype, objectname, PG_PropStr::bordersize, (*_mid)[UNPRESSED].bordersize);
00178 t->GetProperty(widgettype, objectname, PG_PropStr::bordersize, (*_mid)[PRESSED].bordersize);
00179 t->GetProperty(widgettype, objectname, PG_PropStr::bordersize, (*_mid)[HIGHLITED].bordersize);
00180
00181 t->GetProperty(widgettype, objectname, PG_PropStr::bordersize0, (*_mid)[UNPRESSED].bordersize);
00182 t->GetProperty(widgettype, objectname, PG_PropStr::bordersize1, (*_mid)[PRESSED].bordersize);
00183 t->GetProperty(widgettype, objectname, PG_PropStr::bordersize2, (*_mid)[HIGHLITED].bordersize);
00184
00185 t->GetProperty(widgettype, objectname, PG_PropStr::transparency0, (*_mid)[UNPRESSED].transparency);
00186 t->GetProperty(widgettype, objectname, PG_PropStr::transparency1, (*_mid)[PRESSED].transparency);
00187 t->GetProperty(widgettype, objectname, PG_PropStr::transparency2, (*_mid)[HIGHLITED].transparency);
00188
00189 t->GetProperty(widgettype, objectname, PG_PropStr::iconindent, _mid->iconindent);
00190
00191 const std::string& s = t->FindString(widgettype, objectname, PG_PropStr::label);
00192 if(!s.empty()) {
00193 SetText(s);
00194 }
00195
00196 PG_Widget::LoadThemeStyle(widgettype, objectname);
00197 }
00198
00199 void PG_Button::SetBorderColor(int b, const PG_Color& color) {
00200 my_colorBorder[b][0] = color;
00201 }
00202
00204 void PG_Button::eventSizeWidget(Uint16 w, Uint16 h) {
00205 FreeSurfaces();
00206 }
00207
00209 void PG_Button::FreeSurfaces() {
00210 PG_ThemeWidget::DeleteThemedSurface((*_mid)[UNPRESSED].srf);
00211 (*_mid)[UNPRESSED].srf = NULL;
00212
00213 PG_ThemeWidget::DeleteThemedSurface((*_mid)[HIGHLITED].srf);
00214 (*_mid)[HIGHLITED].srf = NULL;
00215
00216 PG_ThemeWidget::DeleteThemedSurface((*_mid)[PRESSED].srf);
00217 (*_mid)[PRESSED].srf = NULL;
00218 }
00219
00220 void PG_Button::FreeIcons() {
00221
00222 if(!_mid->free_icons) {
00223 return;
00224 }
00225
00226 if((*_mid)[UNPRESSED].srf_icon) {
00227 PG_Application::UnloadSurface((*_mid)[UNPRESSED].srf_icon);
00228 (*_mid)[UNPRESSED].srf_icon = NULL;
00229 }
00230
00231 if((*_mid)[HIGHLITED].srf_icon) {
00232 PG_Application::UnloadSurface((*_mid)[HIGHLITED].srf_icon);
00233 (*_mid)[HIGHLITED].srf_icon = NULL;
00234 }
00235
00236 if((*_mid)[PRESSED].srf_icon) {
00237 PG_Application::UnloadSurface((*_mid)[PRESSED].srf_icon);
00238 (*_mid)[PRESSED].srf_icon = NULL;
00239 }
00240
00241 _mid->free_icons = false;
00242 }
00243
00245 void PG_Button::eventMouseEnter() {
00246 if (!(_mid->togglemode && _mid->isPressed)) {
00247 _mid->state = HIGHLITED;
00248 }
00249
00250 Update();
00251 PG_Widget::eventMouseEnter();
00252 }
00253
00255 void PG_Button::eventMouseLeave() {
00256
00257 if(_mid->state == HIGHLITED || !(_mid->behaviour & MSGCAPTURE) ) {
00258 (_mid->togglemode && _mid->isPressed) ? _mid->state = PRESSED : _mid->state = UNPRESSED;
00259 }
00260
00261 Update();
00262 PG_Widget::eventMouseLeave();
00263 }
00264
00266 bool PG_Button::eventMouseButtonDown(const SDL_MouseButtonEvent* button) {
00267 if (!button)
00268 return false;
00269
00270 if(button->button == 1) {
00271 _mid->state = PRESSED;
00272
00273 if ( _mid->behaviour & MSGCAPTURE ) {
00274 SetCapture();
00275 }
00276
00277 Update();
00278
00279 if ( _mid->behaviour & SIGNALONCLICK ) {
00280 sigGlobalClick(this);
00281 sigClick(this);
00282 }
00283
00284 return true;
00285 }
00286
00287 return false;
00288 }
00289
00291 bool PG_Button::eventMouseButtonUp(const SDL_MouseButtonEvent* button) {
00292 if (!button)
00293 return false;
00294
00295 if(button->button != 1) {
00296 return false;
00297 }
00298
00299
00300 if (!IsMouseInside()) {
00301 if (!_mid->togglemode || !_mid->isPressed) {
00302 _mid->state = UNPRESSED;
00303 }
00304
00305 if ( _mid->behaviour & MSGCAPTURE )
00306 ReleaseCapture();
00307
00308 Update();
00309 return false;
00310 }
00311
00312 if(_mid->togglemode) {
00313 if(!_mid->isPressed) {
00314 _mid->state = PRESSED;
00315 _mid->isPressed = true;
00316 } else {
00317 _mid->state = HIGHLITED;
00318 _mid->isPressed = false;
00319 }
00320 } else {
00321 _mid->state = HIGHLITED;
00322 _mid->isPressed = false;
00323 }
00324
00325 if ( _mid->behaviour & MSGCAPTURE )
00326 ReleaseCapture();
00327
00328 Update();
00329
00330 if ( _mid->behaviour & SIGNALONRELEASE ) {
00331 sigGlobalClick(this);
00332 sigClick(this);
00333 }
00334
00335 return true;
00336 }
00337
00339 bool PG_Button::SetIcon(const std::string& filenameup, const std::string& filenamedown, const std::string& filenameover, const PG_Color& colorkey) {
00340 if(!SetIcon(filenameup, filenamedown, filenameover)) {
00341 return false;
00342 }
00343
00344 if((*_mid)[UNPRESSED].srf_icon != NULL) {
00345 SDL_SetColorKey((*_mid)[UNPRESSED].srf_icon, SDL_SRCCOLORKEY, colorkey);
00346 }
00347
00348 if((*_mid)[HIGHLITED].srf_icon != NULL) {
00349 SDL_SetColorKey((*_mid)[HIGHLITED].srf_icon, SDL_SRCCOLORKEY, colorkey);
00350 }
00351
00352 if((*_mid)[PRESSED].srf_icon != NULL) {
00353 SDL_SetColorKey((*_mid)[PRESSED].srf_icon, SDL_SRCCOLORKEY, colorkey);
00354 }
00355
00356 return true;
00357 }
00358
00359 bool PG_Button::SetIcon(const std::string& filenameup, const std::string& filenamedown, const std::string& filenameover) {
00360 SDL_Surface* icon0 = PG_Application::LoadSurface(filenameup);
00361 SDL_Surface* icon1 = PG_Application::LoadSurface(filenameover);
00362 SDL_Surface* icon2 = PG_Application::LoadSurface(filenamedown);
00363
00364 if(icon0 == NULL) {
00365 return false;
00366 }
00367
00368 FreeIcons();
00369
00370 (*_mid)[UNPRESSED].srf_icon = icon0;
00371 (*_mid)[HIGHLITED].srf_icon = icon1;
00372 (*_mid)[PRESSED].srf_icon = icon2;
00373 _mid->free_icons = true;
00374
00375 Update();
00376 return true;
00377 }
00378
00379
00381 bool PG_Button::SetIcon(SDL_Surface* icon_up, SDL_Surface* icon_down,SDL_Surface* icon_over, bool freeSurfaces) {
00382
00383 if(!icon_up && !icon_down && !icon_over) {
00384 return false;
00385 }
00386
00387 FreeIcons();
00388
00389 (*_mid)[UNPRESSED].srf_icon = icon_up;
00390 (*_mid)[HIGHLITED].srf_icon = icon_over;
00391 (*_mid)[PRESSED].srf_icon = icon_down;
00392
00393 _mid->free_icons = freeSurfaces;
00394
00395 return true;
00396 }
00397
00398 SDL_Surface* PG_Button::GetIcon(STATE num) {
00399 return (*_mid)[num].srf_icon;
00400 }
00401
00403 void PG_Button::SetBorderSize(int norm, int pressed, int high) {
00404
00405 if(norm >= 0) {
00406 (*_mid)[UNPRESSED].bordersize = norm;
00407 }
00408
00409 if(pressed >= 0) {
00410 (*_mid)[PRESSED].bordersize = pressed;
00411 }
00412
00413 if(high >= 0) {
00414 (*_mid)[HIGHLITED].bordersize = high;
00415 }
00416 }
00417
00419 void PG_Button::SetToggle(bool bToggle) {
00420 _mid->togglemode = bToggle;
00421 }
00422
00424 void PG_Button::SetPressed(bool pressed) {
00425 if(!_mid->togglemode)
00426 return;
00427
00428 _mid->isPressed = pressed;
00429 _mid->state = (_mid->isPressed ? PRESSED : UNPRESSED);
00430
00431 Update();
00432 }
00433 void PG_Button::SetTransparency(Uint8 t, bool bRecursive) {
00434 (*_mid)[UNPRESSED].transparency = t;
00435 (*_mid)[PRESSED].transparency = t;
00436 (*_mid)[HIGHLITED].transparency = t;
00437
00438 if(!bRecursive || (GetChildList() == NULL)) {
00439 return;
00440 }
00441
00442 for(PG_Widget* i = GetChildList()->first(); i != NULL; i = i->next()) {
00443 i->SetTransparency(t, true);
00444 }
00445 }
00446
00448 void PG_Button::SetTransparency(Uint8 norm, Uint8 pressed, Uint8 high) {
00449 (*_mid)[UNPRESSED].transparency = norm;
00450 (*_mid)[PRESSED].transparency = pressed;
00451 (*_mid)[HIGHLITED].transparency = high;
00452 }
00453
00457 void PG_Button::SetShift(int pixelshift) {
00458 _mid->pressShift = pixelshift;
00459 }
00460
00461
00462 void PG_Button::SetBehaviour( int behaviour ) {
00463 _mid->behaviour = behaviour;
00464 }
00465
00466
00468 void PG_Button::eventButtonSurface(SDL_Surface** surface, STATE newstate, Uint16 w, Uint16 h) {
00469 if (!surface)
00470 return;
00471
00472 PG_Rect r(0, 0, w, h);
00473
00474
00475 PG_ThemeWidget::DeleteThemedSurface(*surface);
00476
00477
00478 *surface = PG_ThemeWidget::CreateThemedSurface(
00479 r,
00480 &((*_mid)[newstate].gradState),
00481 (*_mid)[newstate].background,
00482 (*_mid)[newstate].backMode,
00483 (*_mid)[newstate].backBlend);
00484 }
00485
00487 void PG_Button::SetGradient(STATE state, const PG_Gradient& gradient) {
00488 (*_mid)[state].gradState = gradient;
00489 }
00490
00491 void PG_Button::SetBackground(STATE state, SDL_Surface* background, PG_Draw::BkMode mode) {
00492
00493 if(!background) {
00494 return;
00495 }
00496
00497 (*_mid)[state].background = background;
00498 (*_mid)[state].backMode = mode;
00499 }
00500
00502 bool PG_Button::GetPressed() {
00503 if(_mid->togglemode) {
00504 return _mid->isPressed;
00505 } else {
00506 return (_mid->state == PRESSED);
00507 }
00508 }
00509
00510 void PG_Button::eventBlit(SDL_Surface* srf, const PG_Rect& src, const PG_Rect& dst) {
00511 PG_Rect rect = *this;
00512 PG_Rect r;
00513 PG_Rect my_src, my_dst;
00514 SDL_Surface** surface;
00515
00516 Uint8 t = 0;
00517
00518
00519 surface = &((*_mid)[UNPRESSED].srf);
00520 if(*surface == NULL) {
00521 FreeSurfaces();
00522
00523 eventButtonSurface(surface, UNPRESSED, w, h);
00524 if(*surface) {
00525 SDL_SetAlpha(*surface, SDL_SRCALPHA, 255-(*_mid)[UNPRESSED].transparency);
00526 }
00527
00528 surface = &((*_mid)[PRESSED].srf);
00529 eventButtonSurface(surface, PRESSED, w, h);
00530 if(*surface) {
00531 SDL_SetAlpha(*surface, SDL_SRCALPHA, 255-(*_mid)[PRESSED].transparency);
00532 }
00533
00534 surface = &((*_mid)[HIGHLITED].srf);
00535 eventButtonSurface(surface, HIGHLITED, w, h);
00536 if(*surface) {
00537 SDL_SetAlpha(*surface, SDL_SRCALPHA, 255-(*_mid)[HIGHLITED].transparency);
00538 }
00539 }
00540
00541
00542 t = (*_mid)[_mid->state].transparency;
00543 srf = (*_mid)[_mid->state].srf;
00544
00545
00546 PG_Application::ScreenLocker locker(true);
00547
00548 if(t != 255) {
00549 SDL_SetAlpha(srf, SDL_SRCALPHA, 255-t);
00550 PG_Draw::BlitSurface(srf, src, PG_Application::GetScreen(), dst);
00551 }
00552
00553
00554 SDL_Surface* iconsrf;
00555 if(_mid->state == PRESSED) {
00556 if((*_mid)[PRESSED].srf_icon == 0) {
00557 iconsrf = (*_mid)[UNPRESSED].srf_icon;
00558 } else {
00559 iconsrf = (*_mid)[PRESSED].srf_icon;
00560 }
00561 } else if(_mid->state == HIGHLITED) {
00562 if((*_mid)[HIGHLITED].srf_icon == 0) {
00563 iconsrf = (*_mid)[UNPRESSED].srf_icon;
00564 } else {
00565 iconsrf = (*_mid)[HIGHLITED].srf_icon;
00566 }
00567 } else {
00568 iconsrf = (*_mid)[UNPRESSED].srf_icon;
00569 }
00570
00571 int tw = my_width;
00572 int shift = (((_mid->state == PRESSED) || (_mid->togglemode && _mid->isPressed)) ? 1 : 0) * _mid->pressShift;
00573
00574 if(iconsrf) {
00575
00576 int dx = my_text.empty() ? (rect.my_width - iconsrf->w) / 2 : _mid->iconindent;
00577 int dy = (rect.my_height - iconsrf->h) >> 1;
00578
00579 r.my_xpos = rect.my_xpos + dx + shift;
00580 r.my_ypos = rect.my_ypos + dy + shift;
00581 r.my_width = iconsrf->w;
00582 r.my_height = iconsrf->h;
00583
00584
00585 GetClipRects(my_src, my_dst, r);
00586
00587
00588 PG_Draw::BlitSurface(iconsrf, my_src, PG_Application::GetScreen(), my_dst);
00589
00590 tw -= (iconsrf->w + _mid->iconindent);
00591 }
00592
00593
00594 if(!my_text.empty()) {
00595 Uint16 w, h;
00596 GetTextSize(w, h);
00597
00598 int tx = (tw - w)/2 + shift;
00599 int ty = ((my_height - h)/2) + shift;
00600
00601 if (iconsrf) {
00602 tx += (iconsrf->w + _mid->iconindent);
00603 }
00604
00605 DrawText(tx, ty, my_text);
00606 }
00607
00608 bool i0, i1;
00609
00610 if(!_mid->togglemode) {
00611 i0 = (_mid->state == PRESSED) ? true : false;
00612 i1 = (_mid->state == PRESSED) ? false : true;
00613 } else {
00614 i0 = (_mid->isPressed) ? true : false;
00615 i1 = (_mid->isPressed) ? false : true;
00616 }
00617
00618 DrawBorder(PG_Rect(0, 0, Width(), Height()), (*_mid)[_mid->state].bordersize, i1);
00619 }
00620
00621 void PG_Button::SetBlendLevel(STATE mode, Uint8 blend) {
00622 (*_mid)[mode].backBlend = blend;
00623 }
00624
00625 Uint8 PG_Button::GetBlendLevel(STATE mode) {
00626 return (*_mid)[mode].backBlend;
00627 }
00628
00629 void PG_Button::SetSizeByText(int Width, int Height, const std::string& Text) {
00630 Width += 2 * (*_mid)[UNPRESSED].bordersize + _mid->pressShift;
00631
00632 SDL_Surface* srf = (*_mid)[UNPRESSED].srf_icon;
00633
00634 if (srf == NULL) {
00635 PG_Widget::SetSizeByText(Width, Height, Text);
00636 eventSizeWidget(my_width, my_height);
00637 return;
00638 }
00639
00640 Uint16 w,h;
00641 int baselineY;
00642
00643 if(Text.empty()) {
00644 if (!PG_FontEngine::GetTextSize(my_text, GetFont(), &w, &h, &baselineY)) {
00645 return;
00646 }
00647 } else {
00648 PG_String ytext = Text;
00649 if (!PG_FontEngine::GetTextSize(ytext, GetFont(), &w, &h, &baselineY)) {
00650 return;
00651 }
00652 }
00653
00654 Uint16 dx = srf->w + Width;
00655
00656 my_width = (srf->w > w) ? dx : w + dx;
00657 my_height = PG_MAX(srf->h, h + baselineY) + Height;
00658
00659 eventSizeWidget(my_width, my_height);
00660 }
00661
00662 void PG_Button::SetIconIndent(Uint16 indent) {
00663 _mid->iconindent = indent;
00664 }
00665
00666 void PG_Button::SetText(const std::string& text)
00667 {
00668 extractAndStoreHotkey( text );
00669 PG_Widget::SetText( text );
00670 }
00671
00672
00673 bool PG_Button::eventKeyDown (const SDL_KeyboardEvent *key)
00674 {
00675 if ( checkForHotkey( key )) {
00676 sigClick( this );
00677 return true;
00678 }
00679 return false;
00680 }
00681