widget.cpp

Go to the documentation of this file.
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 &region) {
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 }

Generated Fri Jul 28 19:23:01 2006.
Copyright © 1998-2003 by the respective authors.

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.