lugre_widget.cpp

Go to the documentation of this file.
00001 #include "lugre_widget.h"
00002 #include "lugre_gfx2D.h"
00003 #include "lugre_scripting.h"
00004 #include "lugre_input.h"
00005 #include <OgreOverlay.h>
00006 
00007 
00008 namespace Lugre {
00009 
00010 /*
00011 notes :
00012 
00013 mbIgnoreMouseOver : widget/dialog flag to not be found via GetWidgetUnderPos, for frames etc
00014 todo : tooltip handling entirely inside lua (onMouseEnter,onMouseLeave,Stepper)
00015 todo : drag&drop handling also mostly inside lua ? (onClick, Stepper:StartDrag if over distance, onMouseEnter (dropzones)..)
00016 TODO : drag & drop
00017 TODO : scrollbar-drag ?
00018 */
00019 
00020 #define kWidgetDialogOverlayZOrderStart 50
00021 #define kWidgetDialogOverlayZOrderScale 5
00022 #define kWidgetCursorOverlayZOrder      640
00023 // max save dialogs = (kWidgetCursorOverlayZOrder - kWidgetDialogOverlayZOrderStart) / kWidgetDialogOverlayZOrderScale
00024     
00025 cDialogManager::cDialogManager() {}
00026 
00027 // commands
00028 cDialog*    cDialogManager::MyCreateDialog  () {
00029     cDialog* res = new cDialog(kWidgetDialogOverlayZOrderStart+mlDialogs.size()*kWidgetDialogOverlayZOrderScale);
00030     mlDialogs.push_back(res);
00031     return res;
00032 }
00033 
00034 void        cDialogManager::DestroyDialog   (cDialog* pDialog) {
00035     if (!pDialog) return;
00036     mlDialogs.remove(pDialog);
00037     
00038     std::list<cWidget*> mycopy(pDialog->mlRootWidget); // use a copy of the list to avoid breakting iterator by automatic unregistering
00039     for (std::list<cWidget*>::iterator itor=mycopy.begin();itor!=mycopy.end();++itor) 
00040         pDialog->DestroyWidget(*itor); // this might trigger callbacks, must be outside dialog destructor
00041     
00042     delete pDialog;
00043     Reorder();
00044 }
00045 
00046 void        cDialogManager::BringToFront    (cDialog* pDialog) {
00047     mlDialogs.remove(pDialog);
00048     mlDialogs.push_back(pDialog);
00049     Reorder();
00050 }
00051 
00052 void        cDialogManager::SendToBack  (cDialog* pDialog) {
00053     mlDialogs.remove(pDialog);
00054     mlDialogs.push_front(pDialog);
00055     Reorder();
00056 }
00057 
00058 void        cDialogManager::Reorder         () {
00059     size_t i = 0; // SetZOrder must be within 0 and 650
00060     for (std::list<cDialog*>::iterator itor=mlDialogs.begin();itor!=mlDialogs.end();++itor,++i)
00061         (*itor)->SetZOrder(kWidgetDialogOverlayZOrderStart + i*kWidgetDialogOverlayZOrderScale);
00062 }
00063 
00065 cDialog*    cDialogManager::GetDialogUnderPos       (const size_t x,const size_t y) {
00066     cDialog* res = 0;
00067     for (std::list<cDialog*>::iterator itor=mlDialogs.begin();itor!=mlDialogs.end();++itor) 
00068         if ((*itor)->IsUnderPos(x,y)) res = (*itor);
00069     return res;
00070 }
00071 
00072 cWidget*    cDialogManager::GetWidgetUnderPos       (const size_t x,const size_t y) {
00073     /*
00074     obsolete (07.10.2006)
00075     cDialog* dialog = GetDialogUnderPos(x,y);
00076     if (!dialog) return 0;
00077     return dialog->GetWidgetUnderPos(x,y);
00078     */
00079     cWidget* res = 0;
00080     cWidget* cur;
00081     for (std::list<cDialog*>::iterator itor=mlDialogs.begin();itor!=mlDialogs.end();++itor) {
00082         cur = (*itor)->GetWidgetUnderPos(x,y);
00083         if (cur) res = cur;
00084     }
00085     return res;
00086 }
00087 
00088 
00089 
00090 // ###############################################################################
00091 
00092 
00093 
00094 
00095 cDialog::cDialog () : mbVisible(false), miUID(0) {}
00096     
00097 cDialog::cDialog (const size_t iInitialZOrder) : mbVisible(true) {
00098     static size_t iLastDialogUID = 0;
00099     miUID = ++iLastDialogUID;
00100     mpOverlay = cGfx2D::CreateOverlay(cGfx2D::GetUniqueName().c_str(),iInitialZOrder);
00101 }
00102 
00103 cDialog::~cDialog() {
00104     // don't do anything that might trigger a callback in the destructor, use DestroyDialog() instead
00105     assert(mlRootWidget.size() == 0 && "some widgets didn't deregister themselves");
00106     mlRootWidget.clear();
00107     cGfx2D::DestroyOverlay(mpOverlay);
00108 }
00109 
00110 cWidget*    cDialog::CreateWidget       (cWidget* pParent) {
00111     cWidget* res = new cWidget(this,pParent);
00112     if (!pParent) mlRootWidget.push_back(res); // only insert root parents
00113     if (pParent) pParent->AttachChild(res);
00114     return res;
00115 }
00116 
00117 void    cDialog::DestroyWidget          (cWidget* pWidget) {
00118     assert(pWidget);
00119     if (!pWidget || pWidget->mpDialog != this) return;
00120             
00121     // release children
00122     std::list<cWidget*> mycopy(pWidget->mlChild); // use a copy of the list to avoid breakting iterator by automatic unregistering
00123     for (std::list<cWidget*>::iterator itor=mycopy.begin();itor!=mycopy.end();++itor)
00124         (*itor)->Destroy();  // this might trigger callbacks, must be outside dialog destructor
00125         
00126     if (!pWidget->mpParent) mlRootWidget.remove(pWidget);
00127     if (pWidget->mpParent) pWidget->mpParent->DetachChild(pWidget);
00128     delete pWidget;
00129 }
00130 
00131 void    cDialog::SetZOrder              (const size_t iZOrder) { 
00132     mpOverlay->setZOrder(iZOrder);
00133     
00134     // work around Ogre::Overlay::setZOrder() bug (dagon 1.2.4) (multiplication with 100 was missing)
00135     Ogre::Overlay::Overlay2DElementsIterator itor = mpOverlay->get2DElementsIterator();
00136     while (itor.hasMoreElements()) itor.getNext()->_notifyZOrder(iZOrder*100);
00137 }
00138 
00139 bool        cDialog::IsUnderPos         (const size_t x,const size_t y) {
00140     if (!mbVisible) return false;
00141     for (std::list<cWidget*>::iterator itor=mlRootWidget.begin();itor!=mlRootWidget.end();++itor) 
00142         if ((*itor)->IsUnderPos(x,y)) return true;
00143     return false;
00144 }
00145 
00146 cWidget*    cDialog::GetWidgetUnderPos  (const size_t x,const size_t y) {
00147     if (!mbVisible) return 0;
00148     cWidget* res = 0;
00149     cWidget* child;
00150     for (std::list<cWidget*>::iterator itor=mlRootWidget.begin();itor!=mlRootWidget.end();++itor) {
00151         if (!(*itor)->mbClipChildsHitTest || (*itor)->IsUnderPos(x,y)) {
00152             child = (*itor)->GetChildUnderPos(x,y);
00153             if (child) {
00154                 res = child;
00155             } else if ((*itor)->IsUnderPos(x,y)) {
00156                 res = (*itor); // prefer childs, but take the parent if none are found
00157             }
00158         }
00159     }
00160     return res;
00161 }
00162 
00163 void    cDialog::BringToFront           () { 
00164     cDialogManager::GetSingleton().BringToFront(this); 
00165 }
00166 
00167 void    cDialog::SendToBack             () { 
00168     cDialogManager::GetSingleton().SendToBack(this); 
00169 }
00170 
00171 void    cDialog::SetVisible             (const bool bVisible) {
00172     if (bVisible == mbVisible) return;
00173     mbVisible = bVisible;
00174     if (bVisible) 
00175             mpOverlay->show(); 
00176     else    mpOverlay->hide();
00177 }
00178 
00179 bool    cDialog::GetVisible             () {
00180     return mbVisible;
00181 }
00182 
00183 
00184 
00185 
00186 // ###############################################################################
00187 
00188 
00190 cWidget::cWidget() : miUID(0), mpGfx2D(0), mpDialog(0), mpParent(0), mpBitMask(0) {}
00191 
00192 cWidget::cWidget(cDialog* pDialog,cWidget* pParent) : 
00193     mpDialog(pDialog), mpParent(0), mbIgnoreMouseOver(false), mbClipChildsHitTest(true), mpBitMask(0) {
00194     static size_t iLastWidgetUID = 0;
00195     miUID = ++iLastWidgetUID;
00196     assert(mpDialog);
00197     //l = t = w = h = 0;
00198     //cl = ct = cw = ch = 0;
00199     mpGfx2D = new cGfx2D(pDialog?pDialog->mpOverlay:0,pParent?pParent->mpGfx2D:0);
00200 }
00201 
00202 cWidget::~cWidget() {
00203     // don't do anything that might trigger a callback in the destructor, use Dialog::DestroyWidget() instead   
00204     assert(mlChild.size() == 0 && "some widgets didn't deregister themselves");
00205     mlChild.clear();
00206     // destroy gfx2d
00207     if (mpGfx2D) { delete mpGfx2D; mpGfx2D = 0; }
00208 }
00209 
00210 void        cWidget::Destroy        () {
00211     if (!mpDialog) return;
00212     mpDialog->DestroyWidget(this);
00213 }
00214 
00215 cWidget*    cWidget::CreateChild        () {
00216     if (!mpDialog) return 0;
00217     return mpDialog->CreateWidget(this);
00218 }
00219 
00220 void        cWidget::AttachChild        (cWidget* pWidget) {
00221     if (!pWidget || pWidget->mpParent) return;
00222     mlChild.push_back(pWidget);
00223     pWidget->mpParent = this;
00224 }
00225 
00226 void        cWidget::DetachChild        (cWidget* pWidget) {
00227     if (!pWidget || pWidget->mpParent != this) return;
00228     mlChild.remove(pWidget);
00229     pWidget->mpParent = 0;
00230 }
00231 
00232 void        cWidget::UpdateClip (const Ogre::Real fMarginL,const Ogre::Real fMarginT,const Ogre::Real fMarginR,const Ogre::Real fMarginB) {
00233     Ogre::Real l = mpGfx2D->GetDerivedLeft() + fMarginL;
00234     Ogre::Real t = mpGfx2D->GetDerivedTop() + fMarginT;
00235     Ogre::Real w = mpGfx2D->GetWidth() - (fMarginL+fMarginR);
00236     Ogre::Real h = mpGfx2D->GetHeight() - (fMarginT+fMarginB);
00237     
00238     for (std::list<cWidget*>::iterator itor=mlChild.begin();itor!=mlChild.end();++itor)
00239         (*itor)->mpGfx2D->SetClip(l,t,w,h);
00240 }
00241 
00242 bool        cWidget::IsUnderPos         (const size_t x,const size_t y) {
00243     if (!mpGfx2D) return false;
00244     if (!mpGfx2D->GetVisible()) return false;
00245     if (mbIgnoreMouseOver) return false;
00246     if (mpBitMask) return mpBitMask->TestBit((int)(x - mpGfx2D->GetDerivedLeft()),(int)(y - mpGfx2D->GetDerivedTop()));
00247     return mpGfx2D->IsPointWithin(x,y);
00248 }
00249 
00251 cWidget*    cWidget::GetChildUnderPos   (const size_t x,const size_t y) {
00252     cWidget* res = 0;
00253     cWidget* child;
00254     for (std::list<cWidget*>::iterator itor=mlChild.begin();itor!=mlChild.end();++itor) {
00255         bool bIsUnder = (*itor)->IsUnderPos(x,y);
00256         if (!(*itor)->mbClipChildsHitTest || bIsUnder) {
00257             child = (*itor)->GetChildUnderPos(x,y);
00258             if (child) {
00259                 res = child;
00260             } else if (bIsUnder) {
00261                 res = (*itor); // prefer childs, but take the parent if none are found
00262             }
00263         }
00264     }
00265     return res;
00266 }
00267 
00268 
00269 /*
00270 void        cWidget::Update         () {
00271     // TODO : IMPLEMENT ME !
00273     
00274 } 
00275 
00276 
00277 // ogre specific stuff
00278 
00279 void        cWidget::UpdateGfx      () {
00280     // TODO : IMPLEMENT ME !
00281     // applies clipped pos and size to gfx (adjust texcoords, save original)
00282 }
00283 */
00284 
00285 
00286 /*
00287 // utilities
00288 // param readout here, so things like texcoords can have default params from inheritance
00289 // first look in widget params, if not found there look in layout params, if not found there return default
00290 // TODO : think this over, maybe layout is the wrong place for this, rather change param-map from lua class ??
00291 std::string cWidget::GetParam       (const char* sName,const char* sDefault="") {}  ///< calls mpLayout->GetParam
00292 float       cWidget::GetParamFloat  (const char* sName,const float fDefault=0.0) {} ///< calls mpLayout->GetParamFloat
00293 int         cWidget::GetParamInt        (const char* sName,const int   iDefault=0) {}       ///< calls mpLayout->GetParamInt
00294 */
00295 
00296 
00297 /* NOTES :
00298 
00299 // cursor
00300 // cursoroverlay with z-order = above-all
00301 // direct creation is too long :
00302 // void     SetCursor       (Ogre::Real cx,Ogre::Real cy,Ogre::Real offx,Ogre::Real offy,Ogre::Real u1,Ogre::Real u2,Ogre::Real v1,Ogre::Real v2,const char* sMat);
00303 // better : empty cursor-overlay-element-container, other overlay elements can be atached dynamically (cursor graphic, tooltip, drag&drop gfx...)
00304 
00305 on change of mpCurDropZone :
00306 bool    NewDropZone::OnDragOver     (cWidget* pDragged,cWidget* pDropZone);  // true if accepts drop ?  callback for draggable ?
00307 void    OldDropZone::OnDragOut      (cWidget* pDragged,cWidget* pDropZone); 
00308 todo : remember or ignore if the dropzone would accept the drop ?
00309 
00310 
00311 NOTES : widgetsize
00312         kSizeType_Pixel,        // 45.0 = 45 pixel
00313         // kSizeType_RelToScreen,   // 0.5 = half of screen // is absolute ?? can be done by reltoparent if direct child ?
00314         kSizeType_RelToParent,  // 0.5 = half of parent size  // not absolute
00315         kSizeType_WeightedRest, // can be anything greater 0, size = unused_space_in_parent * weight_this / weight_sum_of_all_childs
00316 
00317 
00318 
00319 BIG BAD TODO :
00320 
00321 gfx2d.h gfx2d.cpp  : overlays, overlayelements, container...
00322 HUDElement2D verallgemeineren, dass es gfx2d.h benutzt, und nur positionierungszeug macht...
00323 widget benutzt dann auch gfx2d.h
00324 anschauen wie gfx in object und unabhanegig davon benutzt wird
00325 
00326 gfx2d : optioen fuer clip-to-parent ?
00327 gfx2d : methode fuer pos,size auslesen ?  (left,top,w,h)  achtung bei der metrik
00328 gfx2d : kapselt ogre : createoverlay, getscreencx,cy 
00329 
00330 luabinding : gfx2d, dialog, widget
00331 
00332 durch clipping komplett versteckte objekte nicht in die renderpipe, auch die childs nicht !
00333 option fuer colorclippane : clip to full screen
00334 option fuer colorclippane : clip children
00335 
00336 
00337 every-frame sachen :
00338     mouse-hit-tests (mouseover,drag...)
00339     resizing ?
00340     scrolling ?
00341     color-alpha fade ?
00342 
00343 
00344 //dialog::AddRootWidget     (cWidget* pWidget); ///< obsolete : no parent change neccessary, mpOverlay::add2d(      widget->mpOverlayContainer) , widget.mpDialog = this
00345 //dialog::RemoveRootWidget  (cWidget* pWidget); ///< obsolete : no parent change neccessary, mpOverlay::remove2D(   widget->mpOverlayContainer) , widget.mpDialog = 0
00346 
00347 // widget : utilities
00348 // param readout here, so things like texcoords can have default params from inheritance
00349 // first look in widget params, if not found there look in layout params, if not found there return default
00350 // TODO : think this over, maybe layout is the wrong place for this, rather change param-map from lua class ??
00351 //std::string   GetParam        (const char* sName,const char* sDefault="");    ///< calls mpLayout->GetParam
00352 //float         GetParamFloat   (const char* sName,const float fDefault=0.0);   ///< calls mpLayout->GetParamFloat
00353 //int           GetParamInt     (const char* sName,const int   iDefault=0);     ///< calls mpLayout->GetParamInt
00354 
00355 void        widget::Update          (); ///< calculates size and pos from layout (and params)
00356 void        widget::UpdateGfx       (); ///< applies clipped pos and size to gfx (adjust texcoords, save original)
00357 
00358 // std::map<std::string,std::string>    mlParams; // 
00359 // type = table,tr,td,button,checkbox,radiobutton,scrollbar,dropdown,group/pane,tabs(contains panes),
00360 // edittext(singleline),edittext(area),statictext(area)
00361 // dragicon (otherwise graphical representation of self -> clone colorclippane : clone, or render to texture)
00362 
00363 // temporary variables, recalculated with Update()
00364 // mMinSize, mPreferredSize ?
00365 
00366 
00367 
00368 */
00369 };

Generated on Wed Feb 8 06:00:13 2012 for cpp by  doxygen 1.5.6