00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "gui/widgets/window.h"
00023
00024 #include "gui/widgets/layout.h"
00025 #include "gui/widgets/resizegrip.h"
00026 #include "gui/widgets/windowcontainer.h"
00027
00028 #include "gui/gui.h"
00029 #include "gui/palette.h"
00030 #include "gui/skin.h"
00031
00032 #include "configuration.h"
00033 #include "log.h"
00034
00035 #include "resources/image.h"
00036
00037 #include <guichan/exception.hpp>
00038
00039 int Window::instances = 0;
00040 int Window::mouseResize = 0;
00041
00042 Window::Window(const std::string &caption, bool modal, Window *parent,
00043 const std::string &skin):
00044 gcn::Window(caption),
00045 mGrip(0),
00046 mParent(parent),
00047 mLayout(NULL),
00048 mWindowName("window"),
00049 mDefaultSkinPath(skin),
00050 mShowTitle(true),
00051 mModal(modal),
00052 mCloseButton(false),
00053 mDefaultVisible(false),
00054 mSaveVisible(false),
00055 mStickyButton(false),
00056 mSticky(false),
00057 mMinWinWidth(100),
00058 mMinWinHeight(40),
00059 mMaxWinWidth(graphics->getWidth()),
00060 mMaxWinHeight(graphics->getHeight())
00061 {
00062 logger->log("Window::Window(\"%s\")", caption.c_str());
00063
00064 if (!windowContainer)
00065 throw GCN_EXCEPTION("Window::Window(): no windowContainer set");
00066
00067 instances++;
00068
00069 setFrameSize(0);
00070 setPadding(3);
00071 setTitleBarHeight(20);
00072
00073
00074 mSkin = SkinLoader::instance()->load(skin, mDefaultSkinPath);
00075
00076
00077 windowContainer->add(this);
00078
00079 if (mModal)
00080 {
00081 gui->setCursorType(Gui::CURSOR_POINTER);
00082 requestModalFocus();
00083 }
00084
00085
00086 setVisible(false);
00087
00088 addWidgetListener(this);
00089 }
00090
00091 Window::~Window()
00092 {
00093 logger->log("Window::~Window(\"%s\")", getCaption().c_str());
00094
00095 saveWindowState();
00096
00097 delete mLayout;
00098
00099 while (!mWidgets.empty())
00100 delete mWidgets.front();
00101
00102 removeWidgetListener(this);
00103
00104 instances--;
00105
00106 mSkin->instances--;
00107 }
00108
00109 void Window::setWindowContainer(WindowContainer *wc)
00110 {
00111 windowContainer = wc;
00112 }
00113
00114 void Window::draw(gcn::Graphics *graphics)
00115 {
00116 Graphics *g = static_cast<Graphics*>(graphics);
00117
00118 g->drawImageRect(0, 0, getWidth(), getHeight(), mSkin->getBorder());
00119
00120
00121 if (mShowTitle)
00122 {
00123 g->setColor(guiPalette->getColor(Palette::TEXT));
00124 g->setFont(getFont());
00125 g->drawText(getCaption(), 7, 5, gcn::Graphics::LEFT);
00126 }
00127
00128
00129 if (mCloseButton)
00130 {
00131 g->drawImage(mSkin->getCloseImage(),
00132 getWidth() - mSkin->getCloseImage()->getWidth() - getPadding(),
00133 getPadding());
00134 }
00135
00136
00137 if (mStickyButton)
00138 {
00139 Image *button = mSkin->getStickyImage(mSticky);
00140 int x = getWidth() - button->getWidth() - getPadding();
00141 if (mCloseButton)
00142 x -= mSkin->getCloseImage()->getWidth();
00143
00144 g->drawImage(button, x, getPadding());
00145 }
00146
00147 drawChildren(graphics);
00148 }
00149
00150 void Window::setContentSize(int width, int height)
00151 {
00152 width = width + 2 * getPadding();
00153 height = height + getPadding() + getTitleBarHeight();
00154
00155 if (getMinWidth() > width)
00156 width = getMinWidth();
00157 else if (getMaxWidth() < width)
00158 width = getMaxWidth();
00159 if (getMinHeight() > height)
00160 height = getMinHeight();
00161 else if (getMaxHeight() < height)
00162 height = getMaxHeight();
00163
00164 setSize(width, height);
00165 }
00166
00167 void Window::setLocationRelativeTo(gcn::Widget *widget)
00168 {
00169 int wx, wy;
00170 int x, y;
00171
00172 widget->getAbsolutePosition(wx, wy);
00173 getAbsolutePosition(x, y);
00174
00175 setPosition(getX() + (wx + (widget->getWidth() - getWidth()) / 2 - x),
00176 getY() + (wy + (widget->getHeight() - getHeight()) / 2 - y));
00177 }
00178
00179 void Window::setLocationRelativeTo(ImageRect::ImagePosition position,
00180 int offsetX, int offsetY)
00181 {
00182 if (position == ImageRect::UPPER_LEFT)
00183 {
00184 }
00185 else if (position == ImageRect::UPPER_CENTER)
00186 {
00187 offsetX += (graphics->getWidth() - getWidth()) / 2;
00188 }
00189 else if (position == ImageRect::UPPER_RIGHT)
00190 {
00191 offsetX += graphics->getWidth() - getWidth();
00192 }
00193 else if (position == ImageRect::LEFT)
00194 {
00195 offsetY += (graphics->getHeight() - getHeight()) / 2;
00196 }
00197 else if (position == ImageRect::CENTER)
00198 {
00199 offsetX += (graphics->getWidth() - getWidth()) / 2;
00200 offsetY += (graphics->getHeight() - getHeight()) / 2;
00201 }
00202 else if (position == ImageRect::RIGHT)
00203 {
00204 offsetX += graphics->getWidth() - getWidth();
00205 offsetY += (graphics->getHeight() - getHeight()) / 2;
00206 }
00207 else if (position == ImageRect::LOWER_LEFT)
00208 {
00209 offsetY += graphics->getHeight() - getHeight();
00210 }
00211 else if (position == ImageRect::LOWER_CENTER)
00212 {
00213 offsetX += (graphics->getWidth() - getWidth()) / 2;
00214 offsetY += graphics->getHeight() - getHeight();
00215 }
00216 else if (position == ImageRect::LOWER_RIGHT)
00217 {
00218 offsetX += graphics->getWidth() - getWidth();
00219 offsetY += graphics->getHeight() - getHeight();
00220 }
00221
00222 setPosition(offsetX, offsetY);
00223 }
00224
00225 void Window::setMinWidth(int width)
00226 {
00227 mMinWinWidth = width > mSkin->getMinWidth() ? width : mSkin->getMinWidth();
00228 }
00229
00230 void Window::setMinHeight(int height)
00231 {
00232 mMinWinHeight = height > mSkin->getMinHeight() ?
00233 height : mSkin->getMinHeight();
00234 }
00235
00236 void Window::setMaxWidth(int width)
00237 {
00238 mMaxWinWidth = width;
00239 }
00240
00241 void Window::setMaxHeight(int height)
00242 {
00243 mMaxWinHeight = height;
00244 }
00245
00246 void Window::setResizable(bool r)
00247 {
00248 if ((bool) mGrip == r)
00249 return;
00250
00251 if (r)
00252 {
00253 mGrip = new ResizeGrip;
00254 mGrip->setX(getWidth() - mGrip->getWidth() - getChildrenArea().x);
00255 mGrip->setY(getHeight() - mGrip->getHeight() - getChildrenArea().y);
00256 add(mGrip);
00257 }
00258 else
00259 {
00260 remove(mGrip);
00261 delete mGrip;
00262 mGrip = 0;
00263 }
00264 }
00265
00266 void Window::widgetResized(const gcn::Event &event)
00267 {
00268 const gcn::Rectangle area = getChildrenArea();
00269
00270 if (mGrip)
00271 mGrip->setPosition(getWidth() - mGrip->getWidth() - area.x,
00272 getHeight() - mGrip->getHeight() - area.y);
00273
00274 if (mLayout)
00275 {
00276 int w = area.width;
00277 int h = area.height;
00278 mLayout->reflow(w, h);
00279 }
00280 }
00281
00282 void Window::setCloseButton(bool flag)
00283 {
00284 mCloseButton = flag;
00285 }
00286
00287 bool Window::isResizable() const
00288 {
00289 return mGrip;
00290 }
00291
00292 void Window::setStickyButton(bool flag)
00293 {
00294 mStickyButton = flag;
00295 }
00296
00297 void Window::setSticky(bool sticky)
00298 {
00299 mSticky = sticky;
00300 }
00301
00302 void Window::setVisible(bool visible)
00303 {
00304 setVisible(visible, false);
00305 }
00306
00307 void Window::setVisible(bool visible, bool forceSticky)
00308 {
00309 gcn::Window::setVisible((!forceSticky && isSticky()) || visible);
00310 }
00311
00312 void Window::scheduleDelete()
00313 {
00314 windowContainer->scheduleDelete(this);
00315 }
00316
00317 void Window::mousePressed(gcn::MouseEvent &event)
00318 {
00319
00320 gcn::Window::mousePressed(event);
00321
00322 if (event.getButton() == gcn::MouseEvent::LEFT)
00323 {
00324 const int x = event.getX();
00325 const int y = event.getY();
00326
00327
00328 if (mCloseButton)
00329 {
00330 gcn::Rectangle closeButtonRect(
00331 getWidth() - mSkin->getCloseImage()->getWidth() - getPadding(),
00332 getPadding(),
00333 mSkin->getCloseImage()->getWidth(),
00334 mSkin->getCloseImage()->getHeight());
00335
00336 if (closeButtonRect.isPointInRect(x, y))
00337 {
00338 close();
00339 }
00340 }
00341
00342
00343 if (mStickyButton)
00344 {
00345 Image *button = mSkin->getStickyImage(mSticky);
00346 int rx = getWidth() - button->getWidth() - getPadding();
00347 if (mCloseButton)
00348 rx -= mSkin->getCloseImage()->getWidth();
00349 gcn::Rectangle stickyButtonRect(rx, getPadding(),
00350 button->getWidth(), button->getHeight());
00351
00352 if (stickyButtonRect.isPointInRect(x, y))
00353 {
00354 setSticky(!isSticky());
00355 }
00356 }
00357
00358
00359 mouseResize = getResizeHandles(event);
00360 }
00361 }
00362
00363 void Window::close()
00364 {
00365 setVisible(false);
00366 }
00367
00368 void Window::mouseReleased(gcn::MouseEvent &event)
00369 {
00370 if (mGrip && mouseResize)
00371 {
00372 mouseResize = 0;
00373 gui->setCursorType(Gui::CURSOR_POINTER);
00374 }
00375
00376
00377 mMoved = false;
00378 }
00379
00380 void Window::mouseExited(gcn::MouseEvent &event)
00381 {
00382 if (mGrip && !mouseResize)
00383 gui->setCursorType(Gui::CURSOR_POINTER);
00384 }
00385
00386 void Window::mouseMoved(gcn::MouseEvent &event)
00387 {
00388 int resizeHandles = getResizeHandles(event);
00389
00390
00391 switch (resizeHandles)
00392 {
00393 case BOTTOM | RIGHT:
00394 gui->setCursorType(Gui::CURSOR_RESIZE_DOWN_RIGHT);
00395 break;
00396 case BOTTOM | LEFT:
00397 gui->setCursorType(Gui::CURSOR_RESIZE_DOWN_LEFT);
00398 break;
00399 case BOTTOM:
00400 gui->setCursorType(Gui::CURSOR_RESIZE_DOWN);
00401 break;
00402 case RIGHT:
00403 case LEFT:
00404 gui->setCursorType(Gui::CURSOR_RESIZE_ACROSS);
00405 break;
00406 default:
00407 gui->setCursorType(Gui::CURSOR_POINTER);
00408 }
00409 }
00410
00411 void Window::mouseDragged(gcn::MouseEvent &event)
00412 {
00413
00414 gcn::Window::mouseDragged(event);
00415
00416
00417 if (isMovable() && mMoved)
00418 {
00419 int newX = std::max(0, getX());
00420 int newY = std::max(0, getY());
00421 newX = std::min(graphics->getWidth() - getWidth(), newX);
00422 newY = std::min(graphics->getHeight() - getHeight(), newY);
00423 setPosition(newX, newY);
00424 }
00425
00426 if (mouseResize && !mMoved)
00427 {
00428 const int dx = event.getX() - mDragOffsetX;
00429 const int dy = event.getY() - mDragOffsetY;
00430 gcn::Rectangle newDim = getDimension();
00431
00432 if (mouseResize & (TOP | BOTTOM))
00433 {
00434 int newHeight = newDim.height + ((mouseResize & TOP) ? -dy : dy);
00435 newDim.height = std::min(mMaxWinHeight,
00436 std::max(mMinWinHeight, newHeight));
00437
00438 if (mouseResize & TOP)
00439 newDim.y -= newDim.height - getHeight();
00440 }
00441
00442 if (mouseResize & (LEFT | RIGHT))
00443 {
00444 int newWidth = newDim.width + ((mouseResize & LEFT) ? -dx : dx);
00445 newDim.width = std::min(mMaxWinWidth,
00446 std::max(mMinWinWidth, newWidth));
00447
00448 if (mouseResize & LEFT)
00449 newDim.x -= newDim.width - getWidth();
00450 }
00451
00452
00453 if (newDim.x < 0)
00454 {
00455 newDim.width += newDim.x;
00456 newDim.x = 0;
00457 }
00458 if (newDim.y < 0)
00459 {
00460 newDim.height += newDim.y;
00461 newDim.y = 0;
00462 }
00463 if (newDim.x + newDim.width > graphics->getWidth())
00464 {
00465 newDim.width = graphics->getWidth() - newDim.x;
00466 }
00467 if (newDim.y + newDim.height > graphics->getHeight())
00468 {
00469 newDim.height = graphics->getHeight() - newDim.y;
00470 }
00471
00472
00473 if (mouseResize & BOTTOM)
00474 {
00475 mDragOffsetY += newDim.height - getHeight();
00476 }
00477 if (mouseResize & RIGHT)
00478 {
00479 mDragOffsetX += newDim.width - getWidth();
00480 }
00481
00482
00483 setDimension(newDim);
00484 }
00485 }
00486
00487 void Window::loadWindowState()
00488 {
00489 const std::string &name = mWindowName;
00490 const std::string skinName = config.getValue(name + "Skin",
00491 mSkin->getFilePath());
00492 assert(!name.empty());
00493
00494 setPosition((int) config.getValue(name + "WinX", mDefaultX),
00495 (int) config.getValue(name + "WinY", mDefaultY));
00496
00497 if (mSaveVisible)
00498 setVisible((bool) config.getValue(name + "Visible", mDefaultVisible));
00499
00500 if (mStickyButton)
00501 setSticky((bool) config.getValue(name + "Sticky", isSticky()));
00502
00503 if (skinName.compare(mSkin->getFilePath()) != 0)
00504 {
00505 mSkin->instances--;
00506 mSkin = SkinLoader::instance()->load(skinName, mDefaultSkinPath);
00507 }
00508
00509 if (mGrip)
00510 {
00511 int width = (int) config.getValue(name + "WinWidth", mDefaultWidth);
00512 int height = (int) config.getValue(name + "WinHeight", mDefaultHeight);
00513
00514 if (getMinWidth() > width)
00515 width = getMinWidth();
00516 else if (getMaxWidth() < width)
00517 width = getMaxWidth();
00518 if (getMinHeight() > height)
00519 height = getMinHeight();
00520 else if (getMaxHeight() < height)
00521 height = getMaxHeight();
00522
00523 setSize(width, height);
00524 }
00525 else
00526 {
00527 setSize(mDefaultWidth, mDefaultHeight);
00528 }
00529 }
00530
00531 void Window::saveWindowState()
00532 {
00533
00534 if (!mWindowName.empty() && mWindowName != "window")
00535 {
00536 config.setValue(mWindowName + "WinX", getX());
00537 config.setValue(mWindowName + "WinY", getY());
00538
00539 if (mSaveVisible)
00540 config.setValue(mWindowName + "Visible", isVisible());
00541
00542 if (mStickyButton)
00543 config.setValue(mWindowName + "Sticky", isSticky());
00544
00545 config.setValue(mWindowName + "Skin", mSkin->getFilePath());
00546
00547 if (mGrip)
00548 {
00549 if (getMinWidth() > getWidth())
00550 setWidth(getMinWidth());
00551 else if (getMaxWidth() < getWidth())
00552 setWidth(getMaxWidth());
00553 if (getMinHeight() > getHeight())
00554 setHeight(getMinHeight());
00555 else if (getMaxHeight() < getHeight())
00556 setHeight(getMaxHeight());
00557
00558 config.setValue(mWindowName + "WinWidth", getWidth());
00559 config.setValue(mWindowName + "WinHeight", getHeight());
00560 }
00561 }
00562 }
00563
00564 void Window::setDefaultSize(int defaultX, int defaultY,
00565 int defaultWidth, int defaultHeight)
00566 {
00567 if (getMinWidth() > defaultWidth)
00568 defaultWidth = getMinWidth();
00569 else if (getMaxWidth() < defaultWidth)
00570 defaultWidth = getMaxWidth();
00571 if (getMinHeight() > defaultHeight)
00572 defaultHeight = getMinHeight();
00573 else if (getMaxHeight() < defaultHeight)
00574 defaultHeight = getMaxHeight();
00575
00576 mDefaultX = defaultX;
00577 mDefaultY = defaultY;
00578 mDefaultWidth = defaultWidth;
00579 mDefaultHeight = defaultHeight;
00580 }
00581
00582 void Window::setDefaultSize()
00583 {
00584 mDefaultX = getX();
00585 mDefaultY = getY();
00586 mDefaultWidth = getWidth();
00587 mDefaultHeight = getHeight();
00588 }
00589
00590 void Window::setDefaultSize(int defaultWidth, int defaultHeight,
00591 ImageRect::ImagePosition position,
00592 int offsetX, int offsetY)
00593 {
00594 int x = 0, y = 0;
00595
00596 if (position == ImageRect::UPPER_LEFT)
00597 {
00598 }
00599 else if (position == ImageRect::UPPER_CENTER)
00600 {
00601 x = (graphics->getWidth() - defaultWidth) / 2;
00602 }
00603 else if (position == ImageRect::UPPER_RIGHT)
00604 {
00605 x = graphics->getWidth() - defaultWidth;
00606 }
00607 else if (position == ImageRect::LEFT)
00608 {
00609 y = (graphics->getHeight() - defaultHeight) / 2;
00610 }
00611 else if (position == ImageRect::CENTER)
00612 {
00613 x = (graphics->getWidth() - defaultWidth) / 2;
00614 y = (graphics->getHeight() - defaultHeight) / 2;
00615 }
00616 else if (position == ImageRect::RIGHT)
00617 {
00618 x = graphics->getWidth() - defaultWidth;
00619 y = (graphics->getHeight() - defaultHeight) / 2;
00620 }
00621 else if (position == ImageRect::LOWER_LEFT)
00622 {
00623 y = graphics->getHeight() - defaultHeight;
00624 }
00625 else if (position == ImageRect::LOWER_CENTER)
00626 {
00627 x = (graphics->getWidth() - defaultWidth) / 2;
00628 y = graphics->getHeight() - defaultHeight;
00629 }
00630 else if (position == ImageRect::LOWER_RIGHT)
00631 {
00632 x = graphics->getWidth() - defaultWidth;
00633 y = graphics->getHeight() - defaultHeight;
00634 }
00635
00636 mDefaultX = x - offsetX;
00637 mDefaultY = y - offsetY;
00638 mDefaultWidth = defaultWidth;
00639 mDefaultHeight = defaultHeight;
00640 }
00641
00642 void Window::resetToDefaultSize()
00643 {
00644 setPosition(mDefaultX, mDefaultY);
00645 setSize(mDefaultWidth, mDefaultHeight);
00646 saveWindowState();
00647 }
00648
00649 int Window::getResizeHandles(gcn::MouseEvent &event)
00650 {
00651 int resizeHandles = 0;
00652 const int y = event.getY();
00653
00654 if (mGrip && y > (int) mTitleBarHeight)
00655 {
00656 const int x = event.getX();
00657
00658 if (!getChildrenArea().isPointInRect(x, y) &&
00659 event.getSource() == this)
00660 {
00661 resizeHandles |= (x > getWidth() - resizeBorderWidth) ? RIGHT :
00662 (x < resizeBorderWidth) ? LEFT : 0;
00663 resizeHandles |= (y > getHeight() - resizeBorderWidth) ? BOTTOM :
00664 (y < resizeBorderWidth) ? TOP : 0;
00665 }
00666
00667 if (event.getSource() == mGrip)
00668 {
00669 mDragOffsetX = x;
00670 mDragOffsetY = y;
00671 resizeHandles |= BOTTOM | RIGHT;
00672 }
00673 }
00674
00675 return resizeHandles;
00676 }
00677
00678 int Window::getGuiAlpha()
00679 {
00680 float alpha = config.getValue("guialpha", 0.8);
00681 return (int) (alpha * 255.0f);
00682 }
00683
00684 Layout &Window::getLayout()
00685 {
00686 if (!mLayout) mLayout = new Layout;
00687 return *mLayout;
00688 }
00689
00690 LayoutCell &Window::place(int x, int y, gcn::Widget *wg, int w, int h)
00691 {
00692 add(wg);
00693 return getLayout().place(wg, x, y, w, h);
00694 }
00695
00696 ContainerPlacer Window::getPlacer(int x, int y)
00697 {
00698 return ContainerPlacer(this, &getLayout().at(x, y));
00699 }
00700
00701 void Window::reflowLayout(int w, int h)
00702 {
00703 assert(mLayout);
00704 mLayout->reflow(w, h);
00705 delete mLayout;
00706 mLayout = NULL;
00707 setContentSize(w, h);
00708 }
00709
00710 void Window::center()
00711 {
00712 setLocationRelativeTo(getParent());
00713 }