00001 /* 00002 libwt - Vassilis Virvilis Toolkit - a widget library 00003 Copyright (C) 2006 Vassilis Virvilis <vasvir2@fastmail.fm> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Lesser General Public 00007 License as published by the Free Software Foundation; either 00008 version 2.1 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 Lesser General Public License for more details. 00014 00015 You should have received a copy of the GNU Lesser General Public 00016 License along with this library; if not, write to the 00017 Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00018 Boston, MA 02111-1307, SA. 00019 */ 00020 00021 #include "sdlinput.h" 00022 00023 #include <wt/application.h> 00024 #include <wt/widget.h> 00025 #include <wt/painter.h> 00026 #include <wt/event.h> 00027 #include <wt/font.h> 00028 #include <wt/trace.h> 00029 00030 namespace Wt { 00031 00032 // static members 00033 FocusData Widget::focus_data_; 00034 00035 Widget::Widget(Widget *parent, const std::string &name, int wflags) 00036 : Object(parent, name), 00037 LayoutItem(), 00038 Pixmap(0, 0, -1, wflags), 00039 hidden(false), 00040 enabled(true), 00041 mouseTracking(false), 00042 focusPolicy(NoFocus), 00043 ownFont(false), 00044 wflags_(wflags), 00045 need_redraw_(false), 00046 bg_flags(0), 00047 bg_alignment(0), 00048 painter_(new Painter), 00049 layout_(0) { 00050 hidden.override.connect(sigc::mem_fun(*this, &Widget::is_hidden)); 00051 // connect to layout recalc 00052 sigc::slot1<void, bool> hidden_slot = 00053 sigc::mem_fun(*this, &Widget::hiddenChanged); 00054 hidden.changed.connect(hidden_slot); 00055 00056 enabled.override.connect(sigc::mem_fun(*this, &Widget::is_enabled)); 00057 00058 void (Widget::*update)() = &Widget::update; 00059 sigc::slot0<void> update_slot = sigc::mem_fun(*this, update); 00060 enabled.changed.connect(update_slot); 00061 00062 // let's put on focus widget's list 00063 focus_data_.push_back(this); 00064 00065 if (wflags & W::ShowModal) { 00066 grabKeyboard(); 00067 grabMouse(); 00068 } 00069 00070 // we are goint to paint it anyway on resizeEvent 00071 resize(sizeHint()); 00072 if (parent) 00073 painter_->setFont(parent->font()); 00074 Application::sendPostedEvents(); 00075 } 00076 00077 static bool isWidget(Object *w) { 00078 return w && dynamic_cast<Widget *>(w); 00079 } 00080 00081 Widget::~Widget() { 00082 if (isShown()) { 00083 /// \todo if we are transparent we should be able to avoid this 00084 update(parentWidget(), geometry()); 00085 } 00086 00087 releaseKeyboard(); 00088 releaseMouse(); 00089 00090 if (hasFocus()) { 00091 /// \todo In case parent is not dead we can do it properly. 00092 /// The else guards us from a recursive nasty crash that 00093 /// shouldn't happen if we had a real tree instead of the 00094 /// focusNextPrevChild() abomination. 00095 if (isWidget(parent())) { 00096 focusNextPrevChild(true); 00097 } else { 00098 /* this is getting worse and worst. We have to check 00099 both sides off the list in order to avoid null dereferencing */ 00100 focus_data_.looseFocus(); 00101 } 00102 } 00103 00104 focus_data_.remove(this); 00105 00106 delete painter_; 00107 } 00108 00109 void Widget::reparent(Widget *new_parent) { 00110 Object::reparent(new_parent); 00111 if (new_parent && !ownFont) 00112 painter_->setFont(new_parent->font()); 00113 } 00114 00115 Point Widget::mapToGlobal(const Point & pos) const { 00116 const Widget *p = this; 00117 Point q(pos); 00118 00119 do { 00120 q += p->geometry().topLeft(); 00121 } while ((p = p->parentWidget())); 00122 return q; 00123 } 00124 00125 Point Widget::mapFromGlobal(const Point & pos) const { 00126 const Widget *p = this; 00127 Point q(pos); 00128 00129 do { 00130 q -= p->geometry().topLeft(); 00131 } while ((p = p->parentWidget())); 00132 return q; 00133 } 00134 00135 Point Widget::mapToParent(const Point & pos) const { 00136 return pos + geometry().topLeft(); 00137 } 00138 00139 Point Widget::mapFromParent(const Point & pos) const { 00140 return pos - geometry().topLeft(); 00141 } 00142 00143 Region Widget::mapToGlobal(const Region & region) const { 00144 Region mapped_region(region); 00145 const Point p1(region.boundingRect().topLeft()); 00146 const Point p2(mapToGlobal(p1)); 00147 const Point dp = p2 - p1; 00148 mapped_region.translate(dp.x(), dp.y()); 00149 return mapped_region; 00150 } 00151 00152 Region Widget::mapToParent(const Region & region) const { 00153 Region mapped_region(region); 00154 const Point p1(region.boundingRect().topLeft()); 00155 const Point p2(mapToParent(p1)); 00156 const Point dp = p2 - p1; 00157 mapped_region.translate(dp.x(), dp.y()); 00158 return mapped_region; 00159 } 00160 00161 void Widget::setBackgroundColor(const Color &color) { 00162 if (painter_->backgroundColor() != color) { 00163 painter_->setBackgroundColor(color); 00164 update(); 00165 } 00166 } 00167 00168 const Color& Widget::backgroundColor() const { 00169 return painter_->backgroundColor(); 00170 } 00171 00172 void Widget::setForegroundColor(const Color &color) { 00173 if (painter_->pen().color() != color) { 00174 painter_->setPen(color); 00175 update(); 00176 } 00177 } 00178 00179 const Color& Widget::foregroundColor() const { 00180 return painter_->pen().color(); 00181 } 00182 00183 bool Widget::setBackgroundPixmapFlags(int flags, int alignment) { 00184 bool changed = false; 00185 00186 if (bg_flags != flags) { 00187 bg_flags = flags; 00188 changed = true; 00189 } 00190 00191 if (bg_alignment != alignment) { 00192 bg_alignment = alignment; 00193 changed = true; 00194 } 00195 00196 return changed; 00197 } 00198 00199 void Widget::setBackgroundPixmap(const Pixmap& pixmap, int flags, int alignment) { 00200 bool changed = (bg_pixmap_ != pixmap); 00201 00202 bg_pixmap_ = pixmap; 00203 00204 changed = setBackgroundPixmapFlags(flags, alignment) || changed; 00205 00206 if (changed) { 00207 updateBackground(); 00208 update(); 00209 } 00210 } 00211 00212 bool Widget::event(Event *e) { 00213 bool handled = true; 00214 00215 //check if the event is claimed by someone else 00216 if (Object::event(e)) 00217 return true; 00218 00219 switch (e->type()) { 00220 case Event::MouseButtonPress: 00221 case Event::MouseButtonRelease: 00222 case Event::MouseButtonDblClick: 00223 case Event::MouseMove: { 00224 MouseEvent *me = static_cast<MouseEvent *>(e); 00225 switch (e->type()) { 00226 case Event::MouseButtonPress: 00227 mousePressEvent(me); 00228 break; 00229 case Event::MouseButtonRelease: 00230 mouseReleaseEvent(me); 00231 break; 00232 case Event::MouseButtonDblClick: 00233 mouseDoubleClickEvent(me); 00234 break; 00235 case Event::MouseMove: 00236 mouseMoveEvent(me); 00237 break; 00238 } 00239 handled = me->isAccepted(); 00240 if (parent() && !handled) { 00241 MouseEvent me_new(me->type(), mapToParent(me->pos()), 00242 me->globalPos(), me->button(), me->state()); 00243 handled = Application::sendEvent(parent(), me_new); 00244 } 00245 } 00246 break; 00247 case Event::KeyPress: { 00248 KeyEvent *kep = static_cast<KeyEvent *>(e); 00249 if (kep->key() == Key_Tab) { 00250 focusNextPrevChild(true); 00251 } else if (kep->key() == Key_Backtab) { 00252 focusNextPrevChild(false); 00253 } else { 00254 keyPressEvent(kep); 00255 } 00256 } 00257 break; 00258 case Event::KeyRelease: { 00259 KeyEvent *ker = static_cast<KeyEvent *>(e); 00260 if (ker->key() != Key_Tab && ker->key() != Key_Backtab) { 00261 keyReleaseEvent(ker); 00262 } 00263 } 00264 break; 00265 case Event::FocusIn: 00266 focusInEvent(static_cast<FocusEvent *>(e)); 00267 break; 00268 case Event::FocusOut: 00269 focusOutEvent(static_cast<FocusEvent *>(e)); 00270 break; 00271 case Event::Enter: 00272 enterEvent(e); 00273 break; 00274 case Event::Leave: 00275 leaveEvent(e); 00276 break; 00277 case Event::Wheel: { 00278 WheelEvent *we = static_cast<WheelEvent *>(e); 00279 wheelEvent(we); 00280 handled = we->isAccepted(); 00281 if (parent() && !handled) { 00282 WheelEvent we_new(mapToParent(we->pos()), 00283 we->delta(), we->state()); 00284 handled = Application::sendEvent(parent(), we_new); 00285 } 00286 } 00287 break; 00288 case Event::Paint: 00289 paintEvent(static_cast<PaintEvent *>(e)); 00290 break; 00291 case Event::Resize: 00292 resizeEvent(static_cast<ResizeEvent *>(e)); 00293 break; 00294 case Event::Move: 00295 moveEvent(static_cast<MoveEvent *>(e)); 00296 break; 00297 case Event::Show: 00298 showEvent(static_cast<ShowEvent *>(e)); 00299 break; 00300 case Event::Hide: 00301 hideEvent(static_cast<HideEvent *>(e)); 00302 break; 00303 case Event::Close: 00304 closeEvent(static_cast<CloseEvent *>(e)); 00305 break; 00306 default: 00307 handled = false; 00308 break; 00309 } 00310 00311 return handled; 00312 } 00313 00314 void Widget::mousePressEvent(MouseEvent *me) { 00315 trace("mouse") << "mousePressEvent for " << this << std::endl; 00316 setFocus(FocusEvent::Mouse); 00317 if (hasFocus()) 00318 me->accept(); 00319 } 00320 void Widget::mouseReleaseEvent(MouseEvent *) { 00321 trace("mouse") << "mouseReleaseEvent for " << this << std::endl; 00322 } 00323 void Widget::mouseDoubleClickEvent(MouseEvent *) { 00324 trace("mouse") << "mouseDoubleClickEvent for " << this << std::endl; 00325 } 00326 void Widget::mouseMoveEvent(MouseEvent *) { 00327 trace("mouse") << "mouseMoveEvent for " << this << std::endl; 00328 } 00329 00330 void Widget::focusInEvent(FocusEvent *) { 00331 trace("focus") << "FocusInEvent for " << this << std::endl; 00332 } 00333 00334 void Widget::focusOutEvent(FocusEvent *) { 00335 trace("focus") << "FocusOutEvent for " << this << std::endl; 00336 } 00337 00338 void Widget::keyPressEvent(KeyEvent *) { 00339 trace("key") << "keyPressEvent for " << this << std::endl; 00340 } 00341 00342 void Widget::keyReleaseEvent(KeyEvent *) { 00343 trace("key") << "keyReleaseEvent for " << this << std::endl; 00344 } 00345 00346 void Widget::enterEvent(Event *) { 00347 trace("mouse") << "enterEvent for " << this << std::endl; 00348 } 00349 void Widget::leaveEvent(Event *) { 00350 trace("mouse") << "leaveEvent for " << this << std::endl; 00351 } 00352 void Widget::wheelEvent(WheelEvent *we) { 00353 trace("mouse") << "wheelEvent for " << this << std::endl; 00354 if (focusPolicy > StrongFocus && hasFocus()) { 00355 focusNextPrevChild((we->delta() > 0)); 00356 we->accept(); 00357 } 00358 } 00359 00360 /** 00361 * 00362 * @param w widget to send clipped paint event 00363 * @param region should be in w coordinates 00364 */ 00365 void Widget::update(Widget *w, const Region ®ion) { 00366 if (w) { 00367 Region r(region); 00368 // clip to parent 00369 trace("paint") << "before clip: " << r << std::endl; 00370 trace("paint") << "clip against: " << w->rect() << std::endl; 00371 r &= w->rect(); 00372 trace("paint") << "after clip: " << r << std::endl; 00373 Application::postEvent(w, new PaintEvent(r, w->autoerase())); 00374 } 00375 } 00376 00377 void Widget::paintEvent(PaintEvent *e) { 00378 // notify top ancestor to redraw us and our children 00379 Region region(e->region()); 00380 trace("paint") << "paintEvent: " << this << " region: " << region << std::endl; 00381 if (need_redraw_) { 00382 if (e->erased()) { 00383 trace("paint") << "paintEvent: Erasing " << this << " region: " << region << std::endl; 00384 erase(); 00385 } 00386 painter_->begin(this, autoclip()); 00387 draw(painter_, region); 00388 painter_->end(); 00389 } 00390 if (parent()) { 00391 update(topParentWidget(), mapToGlobal(region)); 00392 } 00393 } 00394 00395 void Widget::updateBackground() { 00396 if (bg_pixmap_) { 00397 if (bg_flags != Unscaled) { 00398 bg_scaled_ = Pixmap(); 00399 if (bg_flags == Scaled) { 00400 bg_scaled_ = bg_pixmap_.scale(size()); 00401 } else if (bg_flags == Tiled) { 00402 bg_scaled_ = Pixmap(size()); 00403 Painter p(&bg_scaled_); 00404 p.drawTiledPixmap(rect(), bg_pixmap_); 00405 } else { 00406 Warn("Unknown BackgroundImageFlag %d\n", bg_flags); 00407 } 00408 } 00409 } 00410 } 00411 00412 void Widget::resizeEvent(ResizeEvent *) { 00413 updateBackground(); 00414 } 00415 00416 void Widget::moveEvent(MoveEvent *) {} 00417 00418 void Widget::showEvent(ShowEvent *) {} 00419 00420 void Widget::hideEvent(HideEvent *) {} 00421 00422 void Widget::closeEvent(CloseEvent *e) { 00423 e->accept(); 00424 } 00425 00426 /*! 00427 A clever widget can draw only the parts of it that are 00428 specified in the region argument. A not so clever widget 00429 can safely ignore the region argument and draw the entire 00430 widget area. 00431 00432 Keep in mind that double buffering is already implemented 00433 and you can't gain anything by reimplementing it again at 00434 this level. 00435 */ 00436 void Widget::draw(Painter *, const Region&) { 00437 trace("draw") << "drawing: " << this << std::endl; 00438 //after drawing the widget does not need repainting 00439 need_redraw_ = false; 00440 return; 00441 } 00442 00443 void Widget::update(const Rect& r) { 00444 need_redraw_ = true; 00445 update(this, r); 00446 } 00447 00448 void Widget::update() { 00449 update(rect()); 00450 } 00451 00452 void Widget::update(int x, int y, int w, int h) { 00453 update(Rect(x, y, w, h)); 00454 } 00455 00456 void Widget::repaint(const Rect& r, bool erase) { 00457 PaintEvent e(r, erase); 00458 need_redraw_ = true; 00459 Application::sendEvent(this, e); 00460 } 00461 00462 void Widget::repaint(const Region& r, bool erase) { 00463 PaintEvent e(r, erase); 00464 need_redraw_ = true; 00465 Application::sendEvent(this, e); 00466 } 00467 00468 void Widget::repaint(int x, int y, int w, int h, bool erase) { 00469 repaint(Rect(x, y, w, h), erase); 00470 } 00471 00472 void Widget::repaint(bool erase) { 00473 repaint(rect(), erase); 00474 } 00475 00476 void Widget::repaint() { 00477 repaint(!(wflags_ & W::NoAutoErase)); 00478 } 00479 00480 void Widget::resize(int w, int h) { 00481 Size newsize(w, h); 00482 Size oldsize(size()); 00483 00484 if (newsize == oldsize) 00485 return; 00486 00487 w = std::max(w, minimumSize().width()); 00488 w = std::min(w, maximumSize().width()); 00489 h = std::max(h, minimumSize().height()); 00490 h = std::min(h, maximumSize().height()); 00491 newsize.setSize(w, h); 00492 00493 Pixmap::resize(w, h); 00494 Region exposed(geometry()); 00495 Rect r(geometry()); 00496 r.setSize(newsize); 00497 LayoutItem::setGeometry(r); 00498 exposed -= geometry(); 00499 trace("geometry") << this << 00500 " Widget::setGeometry() setting geometry to " << r << std::endl; 00501 00502 Application::postEvent(this, new ResizeEvent(newsize, oldsize)); 00503 update(parentWidget(), exposed); 00504 update(); 00505 } 00506 00507 void Widget::resize(const Size& size) { 00508 resize(size.width(), size.height()); 00509 } 00510 00511 void Widget::move(int x, int y) { 00512 const Point newp(x, y); 00513 const Point oldp(geometry().topLeft()); 00514 00515 if (newp == oldp) 00516 return; 00517 00518 Region exposed(geometry()); 00519 Rect r(geometry()); 00520 r.moveTopLeft(newp); 00521 LayoutItem::setGeometry(r); 00522 exposed -= geometry(); 00523 00524 trace("geometry") << this << 00525 " Widget::setGeometry() setting geometry to " << r << std::endl; 00526 00527 Application::postEvent(this, new MoveEvent(newp, oldp)); 00528 update(parentWidget(), exposed); 00529 update(); 00530 } 00531 00532 void Widget::move(const Point& p) { 00533 move(p.x(), p.y()); 00534 } 00535 00536 void Widget::setGeometry(int x, int y, int w, int h) { 00537 move(x, y); 00538 resize(w, h); 00539 trace("geometry") << this << 00540 " Widget::setGeometry() setting geometry to " << geometry() << std::endl; 00541 } 00542 00543 void Widget::setGeometry(const Rect& r) { 00544 setGeometry(r.left(), r.top(), r.width(), r.height()); 00545 } 00546 00547 /*! Widget::updateGeometry() should call 00548 Widget::setGeometry() if there is no parent */ 00549 void Widget::updateGeometry() { 00550 if (parent()) { 00551 Application::postEvent(parent(), new LayoutHintEvent()); 00552 } 00553 } 00554 00555 void Widget::raise() { 00556 Object *p = parent(); 00557 if (!p) 00558 return; 00559 Object::List& list(p->children()); 00560 list.remove(this); 00561 list.push_back(this); 00562 update(); 00563 } 00564 00565 void Widget::lower() { 00566 Object *p = parent(); 00567 if (!p) 00568 return; 00569 Object::List& list(p->children()); 00570 list.remove(this); 00571 list.push_front(this); 00572 update(); 00573 } 00574 00575 void Widget::setLayout(Layout *layout) { 00576 if (layout_ == layout) 00577 return; 00578 00579 if (layout_) { 00580 delete layout_; 00581 } 00582 00583 layout_ = layout; 00584 00585 if (layout) { 00586 layout->reparent(this); 00587 installEventFilter(layout); 00588 } 00589 // emit signal 00590 layoutChanged(layout); 00591 Application::postEvent(this, new LayoutHintEvent()); 00592 } 00593 00594 void Widget::erase(const Rect& r) { 00595 painter_->begin(this, autoclip()); 00596 00597 painter_->eraseRect(r); 00598 00599 if (bg_pixmap_) { 00600 if (bg_flags == Unscaled) { 00601 Rect aligned = Rect::align(rect(), 00602 bg_pixmap_.size(), bg_alignment); 00603 Point p(std::max(aligned.left(), r.left()), 00604 std::max(aligned.top(), r.top())); 00605 painter_->drawPixmap(p, bg_pixmap_); 00606 } else { 00607 painter_->drawPixmap(Point(0, 0), bg_scaled_); 00608 } 00609 } 00610 painter_->end(); 00611 } 00612 00613 void Widget::erase(const Region& r) { 00614 if (bg_pixmap_) { 00615 const RectArray& ra = r.rects(); 00616 const int n = ra.size(); 00617 for (int i = 0; i < n; i++) { 00618 erase(ra[i]); 00619 } 00620 } else { 00621 painter_->begin(this, autoclip()); 00622 painter_->eraseRegion(r); 00623 painter_->end(); 00624 } 00625 } 00626 00627 void Widget::erase() { 00628 erase(rect()); 00629 } 00630 00631 void Widget::erase(int x, int y, int w, int h) { 00632 erase(Rect(x, y, w, h)); 00633 } 00634 00635 const Font& Widget::font() const { 00636 const Widget *p = parentWidget(); 00637 return (p && !ownFont) ? p->font() : painter_->font(); 00638 } 00639 00640 void Widget::setFont(const Font& new_font) { 00641 Font old_font = font(); 00642 painter_->setFont(new_font); 00643 ownFont = true; 00644 fontChange(old_font); 00645 } 00646 00647 void Widget::unsetFont() { 00648 ownFont = false; 00649 } 00650 00651 void Widget::fontChange(const Font& old_font) { 00652 for (Object::List::const_iterator child(children().begin()), 00653 end(children().end()); child != end; ++child) { 00654 Widget* w = dynamic_cast<Widget *>(*child); 00655 // guard against a non widget (e.g. layout) child. 00656 if (w && !w->ownFont) { 00657 w->painter_->setFont(font()); 00658 w->fontChange(old_font); 00659 } 00660 } 00661 updateGeometry(); 00662 update(); 00663 } 00664 00665 void Widget::drawText(int x, int y, const std::string& text) { 00666 painter_->drawText(x, y, text); 00667 } 00668 00669 void Widget::drawText(const Point& p, const std::string& text) { 00670 painter_->drawText(p, text); 00671 } 00672 00673 Widget *Widget::childAt(const Point& p, bool self_include) const { 00674 Widget *result = 0; 00675 const Rect& r = rect(); 00676 if (isHidden() || !r.contains(p)) { 00677 return result; 00678 } 00679 // we got it. Now let's see if it is spot on some child 00680 for (Object::List::const_iterator child(children().begin()), 00681 end(children().end()); child != end; ++child) { 00682 const Widget* w = dynamic_cast<Widget *>(*child); 00683 // guard against a non widget (e.g. layout) child. 00684 if (w) { 00685 const Point& wp(w->mapFromParent(p)); 00686 Widget *ww = w->childAt(wp, true); 00687 // this ensures we keep the last non NULL one (most raised) 00688 if (ww) 00689 result = ww; 00690 } 00691 } 00692 if (!result && self_include) { 00693 result = const_cast<Widget *>(this); 00694 } 00695 return result; 00696 } 00697 00698 template<typename ITERATOR> 00699 static Widget *findNextWidget(ITERATOR start, ITERATOR finish) { 00700 for (ITERATOR it = start; it != finish; ++it) { 00701 Widget *w = dynamic_cast<Widget *>(*it); 00702 if (w && w->isFocusEnabled(FocusEvent::Tab)) 00703 return w; 00704 } 00705 return 0; 00706 } 00707 00708 bool Widget::isFocusEnabled(int reason) const { 00709 bool allow_focus; 00710 00711 if (!enabled) 00712 return false; 00713 00714 switch (reason) { 00715 case FocusEvent::Mouse: 00716 allow_focus = (focusPolicy & ClickFocus); 00717 break; 00718 case FocusEvent::Tab: 00719 case FocusEvent::Backtab: 00720 allow_focus = (focusPolicy & TabFocus); 00721 break; 00722 case FocusEvent::ActiveWindow: 00723 case FocusEvent::Popup: 00724 case FocusEvent::Shortcut: 00725 case FocusEvent::Other: 00726 default: 00727 allow_focus = (focusPolicy != NoFocus); 00728 break; 00729 } 00730 00731 return allow_focus; 00732 } 00733 00734 void Widget::setFocus(int reason) { 00735 Widget *old_focus = focusWidget(); 00736 if (old_focus == this || !isFocusEnabled(reason)) 00737 return; 00738 if (old_focus) { 00739 Application::postEvent(old_focus, 00740 new FocusEvent(Event::FocusOut, reason)); 00741 } 00742 focus_data_.setFocus(this); 00743 Application::postEvent(this, 00744 new FocusEvent(Event::FocusIn, reason)); 00745 } 00746 00747 /// cycles focus amongs widgets 00748 /*! 00749 \todo use Boost graph or tree in order to make this simple 00750 function and FocusData to carry the meat of the implementation 00751 instead the other way around 00752 00753 \bug Backtab is working unexpectedly 00754 00755 \bug focusNextPrevChild is not working right for widgets with children 00756 */ 00757 bool Widget::focusNextPrevChild(bool next) { 00758 Widget *w = focusWidget(), *w2; 00759 const Object::List& children_ = children(); 00760 00761 trace("focus") << "focusNextPrevChild() for " << this << std::endl; 00762 00763 if (w == this) { 00764 // we got the focus. We have to iterate in children 00765 goto start_cycle; 00766 } else if (w->parent() == this) { 00767 // current focusWidget is our child 00768 if (next) { 00769 Object::List::const_iterator it_; 00770 it_ = find(children_.begin(), 00771 children_.end(), w); 00772 // must exist 00773 assert(it_ != children_.end()); 00774 w2 = findNextWidget(++it_, children_.end()); 00775 } else { 00776 Object::List::const_reverse_iterator rit_; 00777 rit_ = find(children_.rbegin(), 00778 children_.rend(), w); 00779 // must exist 00780 assert(rit_ != children_.rend()); 00781 w2 = findNextWidget(++rit_, children_.rend()); 00782 } 00783 00784 if (!w2) { 00785 // cannot continue cycle 00786 if (!parent()) { 00787 // we didn't d find it and we have nowhere to go 00788 // case: rootwindow with children (end of cycle) 00789 goto start_cycle; 00790 } 00791 // cannot continue cycle let's try father 00792 goto pass_to_parent; 00793 } 00794 } else { 00795 // current focusWidget is not our child 00796 // so let's start cycling starting from this 00797 w2 = this; 00798 } 00799 00800 change_focus: 00801 w2->setFocus((next) ? FocusEvent::Tab : FocusEvent::Backtab); 00802 return true; 00803 00804 start_cycle: 00805 w2 = (next) ? 00806 findNextWidget(children_.begin(), children_.end()) : 00807 findNextWidget(children_.rbegin(), children_.rend()); 00808 if (w2) 00809 goto change_focus; 00810 pass_to_parent: 00811 if (parent()) { 00812 Widget *wp = parentWidget(); 00813 return wp->focusNextPrevChild(next); 00814 } 00815 return false; 00816 } 00817 00818 static void postLayoutHintEventRecursively(Widget *w) { 00819 for (Object::List::const_iterator child(w->children().begin()), 00820 end(w->children().end()); child != end; ++child) { 00821 Widget* ww = dynamic_cast<Widget *>(*child); 00822 // guard against a non widget (e.g. layout) child. 00823 if (ww) { 00824 postLayoutHintEventRecursively(ww); 00825 } 00826 } 00827 Application::postEvent(w, new LayoutHintEvent()); 00828 } 00829 00830 void Widget::hiddenChanged(bool hidden_new) { 00831 if (hidden_new) { 00832 Application::postEvent(this, new HideEvent()); 00833 } else { 00834 // notify layout subsystem since layout hint event 00835 // were disabled while top level widget was hidden 00836 postLayoutHintEventRecursively(this); 00837 Application::postEvent(this, new ShowEvent()); 00838 } 00839 updateGeometry(); 00840 // force a repaint 00841 update(); 00842 } 00843 00844 bool Widget::is_hidden(bool val) const { 00845 if (val) 00846 return true; 00847 00848 // during parent's death parentWidget() is not 00849 // reliable anymore (parent is a simple Object) 00850 const Widget *p = dynamic_cast<Widget *>(parent()); 00851 if (p && p->hidden) 00852 return true; 00853 00854 return false; 00855 } 00856 00857 void Widget::hide() { 00858 releaseKeyboard(); 00859 releaseMouse(); 00860 00861 hidden = true; 00862 } 00863 00864 void Widget::show() { 00865 if (wflags_ & W::ShowModal) { 00866 grabKeyboard(); 00867 grabMouse(); 00868 } 00869 00870 hidden = false; 00871 } 00872 00873 void Widget::setHidden(bool do_hide) { 00874 (do_hide) ? hide() : show(); 00875 } 00876 00877 void Widget::setShown(bool do_show) { 00878 (do_show) ? show() : hide(); 00879 } 00880 00881 bool Widget::is_enabled(bool val) const { 00882 if (!val) 00883 return false; 00884 00885 const Widget *p = parentWidget(); 00886 if (p && !p->enabled) 00887 return false; 00888 00889 return true; 00890 } 00891 00892 void Widget::enable() { 00893 enabled = true; 00894 } 00895 00896 void Widget::disable() { 00897 enabled = false; 00898 } 00899 00900 void Widget::setEnabled(bool do_enable) { 00901 (do_enable) ? enable() : disable(); 00902 } 00903 00904 void Widget::setDisabled(bool do_disable) { 00905 (do_disable) ? disable() : enable(); 00906 } 00907 00908 bool Widget::close() { 00909 return close(false); 00910 } 00911 00912 bool Widget::close(bool destroy) { 00913 CloseEvent ce; 00914 Application::sendEvent(this, ce); 00915 if (!ce.isAccepted()) 00916 return false; 00917 00918 const bool kill = destroy || (wflags_ & W::DestructiveClose); 00919 if (!kill) 00920 hide(); 00921 else 00922 delete this; 00923 00924 return true; 00925 } 00926 00927 Size Widget::sizeHint() const { 00928 return (layout_ ? layout_->sizeHint() << layout_->margin : 00929 LayoutItem::sizeHint()); 00930 } 00931 00932 void Widget::setSizeHint(const Size& size) { 00933 if (size == sizeHint()) 00934 return; 00935 // sizeHint can't be < minmumSize() 00936 Size hint_size = size.expandedTo(minimumSize()); 00937 00938 // we can't set sizeHint in a widget with a layout 00939 if (layout_) 00940 return; 00941 LayoutItem::setSizeHint(hint_size); 00942 updateGeometry(); 00943 } 00944 00945 Size Widget::minimumSize() const { 00946 return (layout_ ? layout_->minimumSize() << layout_->margin : 00947 LayoutItem::minimumSize()); 00948 } 00949 00950 void Widget::setMinimumSize(const Size& size) { 00951 if (size == minimumSize()) 00952 return; 00953 00954 if (layout_) 00955 layout_->setMinimumSize(size >> layout_->margin); 00956 LayoutItem::setMinimumSize(size); 00957 00958 // sizeHint can't be < minmumSize() 00959 Size hint_size = size.expandedTo(minimumSize()); 00960 setSizeHint(hint_size); 00961 00962 updateGeometry(); 00963 } 00964 00965 Size Widget::maximumSize() const { 00966 return (layout_ ? layout_->maximumSize() << layout_->margin : 00967 LayoutItem::maximumSize()); 00968 } 00969 00970 void Widget::setMaximumSize(const Size& size) { 00971 if (size == maximumSize()) 00972 return; 00973 if (layout_) 00974 layout_->setMaximumSize(size >> layout_->margin); 00975 LayoutItem::setMaximumSize(size); 00976 updateGeometry(); 00977 } 00978 00979 SizePolicy Widget::sizePolicy() const { 00980 if (layout_) 00981 return layout_->sizePolicy(); 00982 return LayoutItem::sizePolicy(); 00983 } 00984 00985 void Widget::setSizePolicy(const SizePolicy& size_policy) { 00986 if (size_policy == sizePolicy()) 00987 return; 00988 if (layout_) 00989 layout_->setSizePolicy(size_policy); 00990 LayoutItem::setSizePolicy(size_policy); 00991 updateGeometry(); 00992 } 00993 00994 SizePolicy::ExpandData Widget::expanding() const { 00995 if (layout_) 00996 return layout_->expanding(); 00997 return LayoutItem::expanding(); 00998 } 00999 01000 void Widget::grabKeyboard() { 01001 SDLInput::instance()->setKeyboardGrabber(this); 01002 } 01003 01004 void Widget::releaseKeyboard() { 01005 if (keyboardGrabber() == this) 01006 SDLInput::instance()->releaseKeyboardGrab(); 01007 } 01008 01009 Widget *Widget::keyboardGrabber() { 01010 return SDLInput::instance()->keyboardGrabber(); 01011 } 01012 01013 void Widget::grabMouse() { 01014 SDLInput::instance()->setMouseGrabber(this); 01015 } 01016 01017 void Widget::releaseMouse() { 01018 if (mouseGrabber() == this) 01019 SDLInput::instance()->releaseMouseGrab(); 01020 } 01021 01022 Widget *Widget::mouseGrabber() { 01023 return SDLInput::instance()->mouseGrabber(); 01024 } 01025 01026 }
This document is licensed under the terms of the GNU Free Documentation License and may be freely distributed under the conditions given by this license.