Home || Architecture || Video Search || Visual Search || Scripts || Applications || Important Messages || OGL || Src

ScrollBar.h

Go to the documentation of this file.
00001 #ifndef OglGui_ScrollBar_h
00002 #define OglGui_ScrollBar_h
00003 /*
00004  * Author: Michiel van Liempt
00005  * Changed by Richard van Balen
00006  */
00007 
00008 //#define ORG_BTN
00009 // RvB: Reverted from AllFeedstateback trick to be more in line with XP
00010 //#define ORG_STATEFEEDBACK
00011 
00012 #ifndef OglGui_DirectionButton_h
00013 #include "OglGui/DirectionButton.h"
00014 #endif
00015 
00016 #ifndef OglGui_ScrollBarListener_h
00017 #include "OglGui/ScrollBarListener.h"
00018 #endif
00019 
00020 namespace OglGui
00021 {
00022 
00023 class ScrollBar : public Window, RepeatTimer, ButtonListener
00024 {
00025 public:
00026     ScrollBar(Window* parent, int w, int h, bool horizontal) :
00027         Window(parent, w, h, true)
00028     {
00029         Init(horizontal, horizontal ? h : w);
00030     }
00031 
00032     ScrollBar(Window* parent, int x, int y, int w, int h, bool horizontal) :
00033         Window(parent, x, y, w, h, true)
00034     {
00035         Init(horizontal, horizontal ? h : w);
00036     }
00037 
00038     virtual int
00039     SetState(int nState)
00040     {
00041         mButIncr->SetState(nState ? 1 : 0);
00042         mButDecr->SetState(nState ? 1 : 0);
00043         mButThumb->SetState(nState ? 1 : 0);
00044         return Window::SetState(nState);
00045     }
00046 
00047     // RvB: Ask Michiel if he objects being able to
00048     // retrieve a pointer to the components. If so
00049     // the user could tune the components fully to their taste
00050     // For now I only allow the borderType and roundness to be set
00051     // ***** Decided to grant acces for maximum adjustability
00052 
00053     DirectionButton* ButIncr()
00054     {
00055         return mButIncr;
00056     }
00057 
00058     DirectionButton* ButDecr()
00059     {
00060         return mButDecr;
00061     }
00062 
00063     Button* ButThumb()
00064     {
00065         return mButThumb;
00066     }
00067 
00068 
00069     // Shorthand for Component
00070     enum Comp {
00071         Incr, Thumb, Decr, All
00072     };
00073 
00074     void SetCompBorderType(Comp comp, int type)
00075     {
00076         Window   *wnd = 0;
00077         switch(comp)
00078         {
00079         case All:
00080             mButIncr->SetBorderType(type);
00081             mButDecr->SetBorderType(type);
00082             mButThumb->SetBorderType(type);
00083         break;
00084         case Incr: wnd = mButIncr; break;
00085         case Thumb: wnd = mButThumb; break;
00086         case Decr: wnd = mButDecr; break;
00087         }
00088         if (wnd && comp != All)
00089             wnd->SetBorderType(type);
00090     }
00091 
00092     void SetCompRoundness(Comp comp, float r0, float r1, float r2, float r3)
00093     {
00094         Window   *wnd = 0;
00095         switch(comp)
00096         {
00097         case All:
00098             mButIncr->SetRoundness(r0, r1, r2, r3);
00099             mButDecr->SetRoundness(r0, r1, r2, r3);
00100             mButThumb->SetRoundness(r0, r1, r2, r3);
00101         break;
00102         case Incr: wnd = mButIncr; break;
00103         case Thumb: wnd = mButThumb; break;
00104         case Decr: wnd = mButDecr; break;
00105         }
00106         if (wnd && comp != All)
00107             wnd->SetRoundness(r0, r1, r2, r3);
00108     }
00109 
00110     void SetScrollBarListener(ScrollBarListener* listener, void* data=0)
00111     {
00112         mListener = listener;
00113         mListenerData = data;
00114     }
00115     void SetScrollBarListener(ScrollBarListener* listener, int data)
00116     {
00117         SetScrollBarListener(listener, (void*) data);
00118     }
00119 
00120     void ScrollKeyHandling(bool mode)       { mScrollKeyHandling = mode; }
00121     bool ScrollKeyHandling()                { return mScrollKeyHandling; }
00122 
00123     // Deprecated
00124     void SetLineIncrement(int incr)
00125     {
00126         mScrollLine = incr;
00127     }
00128 
00129     void LineIncrement(int incr)
00130     {
00131         mScrollLine = incr;
00132     }
00133     int LineIncrement()
00134     {
00135         return mScrollLine;
00136     }
00137 
00138     void SetRange(int totalRange, int pageSize) // normally measured in lines
00139     {
00140         bool    tooSmall =  (mHorizontal && mOglWnd->width < 40) ||
00141                             (!mHorizontal && mOglWnd->height < 40);
00142 
00143         mScrollRange = totalRange;
00144         mScrollPage = pageSize;
00145         // reposition thumb
00146         // RvB: Added test on mScrollRange != 0, to prevent zero division
00147         if(totalRange > pageSize && pageSize > 0 && !tooSmall &&
00148            mScrollRange!=0)
00149         {
00150             mButThumb->SetVisible(true);
00151             mButIncr->SetVisible(true);
00152             mButDecr->SetVisible(true);
00153             if (mHorizontal)
00154                 mPixelPage = ((mOglWnd->width - (2*cSbW)) * mScrollPage) /
00155                              mScrollRange;
00156             else
00157                 mPixelPage = ((mOglWnd->height - (2*cSbW)) * mScrollPage) /
00158                              mScrollRange;
00159             // minimal thumb size
00160             if (mPixelPage < 12)
00161                 mPixelPage = 12;
00162 
00163             // if change of range pushes thumb over maximum then reposition
00164             if (mPixelPage + mPixelPos > mPixelRange)
00165             {
00166                 mPixelPos = mPixelRange - mPixelPage;
00167                 // RvB: When resizing, jumpy behavior of content being scrolled
00168                 // occurred.After countless hours of trying different strategies
00169                 // removing next line solved the problem.
00170                 // Although I do allow an inconsistency here (BUT RESULT: MUCH
00171                 // BETTER BEHAVIOUR)
00172                 // This trick should probably be made settable
00173 
00174                 // OnScrollThumb(mPixelPos);
00175             }
00176 
00177             if (mHorizontal)
00178                 oglSys.SetDimensions(mButThumb->GetOGLWND(), mPixelPos + cSbW,
00179                                      0, mPixelPage, cSbW);
00180             else
00181             {
00182                 int y = mOglWnd->height - cSbW - mPixelPos - mPixelPage;
00183                 oglSys.SetDimensions(mButThumb->GetOGLWND(), 0, y, cSbW,
00184                                      mPixelPage);
00185             }
00186         }
00187         else
00188         {   // Too small to show buttons
00189             mButThumb->SetVisible(false);
00190             mButIncr->SetVisible(false);
00191             mButDecr->SetVisible(false);
00192         }
00193     }
00194 
00195     void GetRange(int& totalRange, int& pageSize)
00196     {
00197         totalRange = mScrollRange;
00198         pageSize = mScrollPage;
00199     }
00200 
00201     void
00202     ChangePos(int change)
00203     {
00204         SetNewPos(mScrollPos + change);
00205     }
00206 
00207 
00208     void
00209     SetNewPos(int pos) // still measured in lines
00210     {
00211         if (pos>=mScrollRange - mScrollPage)
00212             pos = mScrollRange - mScrollPage;
00213         if (pos<0)
00214             pos = 0;
00215         if (pos != mScrollPos)
00216         {
00217             mScrollPos = pos;
00218 // RvB: Division by zero
00219 //            mPixelPos = (mPixelRange - mPixelPage) * mScrollPos /
00220 //                        (mScrollRange - mScrollPage);
00221 // RvB Replaced by next lines 
00222             int divider = mScrollRange - mScrollPage;
00223             if (!divider)
00224                 divider = 1;
00225             //mPixelPos = (mPixelRange - mPixelPage) * mScrollPos / divider; // Overflow
00226             mPixelPos = ((mPixelRange - mPixelPage) / (double) divider) * mScrollPos;
00227             if(mListener)
00228                 mListener->OnScroll(this, mScrollPos, mListenerData);
00229             oglSys.UpdateSceneFlag(GetOGLWND(), 1);
00230         }
00231     }
00232 
00233     void
00234     MakeVisible(int pos)
00235     {
00236         if ((pos >= mScrollPos) && (pos < mScrollPos+mScrollPage))
00237             return;
00238         SetNewPos(pos);
00239     }
00240 
00241 
00242     void SetValue(int val)
00243     {
00244         SetNewPos(val);
00245     }
00246 
00247     int GetValue()
00248     {
00249         return mScrollPos;
00250     }
00251 
00252     void
00253     SetPosition(int x, int y, int w, int h)
00254     {
00255         // RvB: Michiel vragen
00256         // SetAllowReposition(false);
00257         mOglWnd->x = x;
00258         mOglWnd->y = y;
00259         mOglWnd->height = h;
00260         mOglWnd->width = w;
00261         if (mHorizontal)
00262             mPixelRange = mOglWnd->width - (2*cSbW);
00263         else
00264             mPixelRange = mOglWnd->height - (2*cSbW);
00265         SetRange(mScrollRange, mScrollPage);
00266     }
00267 
00268     // Positions the buttons within the scrollbar
00269     void
00270     RepositionViewports()
00271     {
00272         OGLWND  *oglWnd = GetOGLWND();
00273 
00274         if (mHorizontal)
00275         {   // normally adjust to wideness of scrollbar
00276             int h = oglWnd->height; 
00277             if (mFixedWide) // If fixedWide, refuse a different wideness
00278                 h = oglWnd->height = mWide;
00279             oglSys.SetDimensions(mButDecr->GetOGLWND(), 0, 0, cSbW, h);
00280             oglSys.SetDimensions(mButThumb->GetOGLWND(), mPixelPos + cSbW,
00281                                  0, mPixelPage, h);
00282             oglSys.SetDimensions(mButIncr->GetOGLWND(), mOglWnd->width - cSbW,
00283                                  0, cSbW, h);
00284         }
00285         else
00286         {   // normally adjust to wideness of scrollbar
00287             int w = oglWnd->width;
00288             if (mFixedWide)// If fixedWide, refuse a different wideness
00289                 w = oglWnd->width = mWide;
00290            // please note that y is reversed
00291             oglSys.SetDimensions(mButDecr->GetOGLWND(), 0,
00292                                  mOglWnd->height - cSbW, w, cSbW);
00293             oglSys.SetDimensions(mButThumb->GetOGLWND(), 0,
00294                                  mOglWnd->height - cSbW - mPixelPos - mPixelPage,
00295                                  w, mPixelPage);
00296             oglSys.SetDimensions(mButIncr->GetOGLWND(), 0, 0, w, cSbW);
00297         }
00298     }
00299 
00300 
00301     virtual void
00302     MouseFunc(INT msg, INT but, INT state, INT x, INT y)
00303     {
00304         if (!GetState() || (state & (oglShift|oglControl)))
00305             return;
00306 
00307         Window::MouseFunc(msg, but, state, x, y);
00308 
00309         // a click here means pageup or pagedown
00310         if ((msg==oglMouseDown || msg==oglMouseDblClick) && but==oglLeftButton) 
00311         {
00312             if (mHorizontal)
00313                 mMouseDownPos = x-cSbW;
00314             else
00315                 mMouseDownPos = y-cSbW;
00316             PropagateScrolling();
00317             mPagePressed = true;
00318             StartRepeatTime();
00319             oglSys.SetAlwaysDraw(mOglWnd, true);
00320         }
00321 
00322         if (msg == oglMouseWheelUp)
00323             ChangePos(-mScrollLine * ((state&oglShift) ? 5 : 1));
00324         if (msg == oglMouseWheelDown)
00325             ChangePos(mScrollLine * ((state&oglShift) ? 5 : 1));
00326 
00327         if (msg == oglMouseMove)
00328         {
00329             if (mHorizontal)
00330                 mMouseDownPos = x-cSbW;
00331             else
00332                 mMouseDownPos = y-cSbW;
00333         }
00334 
00335         if (msg == oglMouseUp && but == oglLeftButton)
00336         {
00337             mPagePressed = false;
00338             oglSys.SetAlwaysDraw(mOglWnd, false);
00339         }
00340 
00341     }
00342 
00343     virtual void
00344     InitDisplayFunc()
00345     {
00346 #ifdef ORG_STATEFEEDBACK
00347         if (GetState()==2 || mButThumb->GetState()==2 ||
00348             mButIncr->GetState()==2 || mButDecr->GetState()==2)
00349         {
00350             mOldBorderBg = GetBorderBackground();
00351             SetBorderBackground(mStateFeedbackColor);
00352         }
00353 #endif
00354         // RvB: Added to make sure sizes are correct
00355         // Bespreken met Michiel, hoe het misschien anders kan
00356         if (mHorizontal)
00357             mPixelRange = mOglWnd->width - (2*cSbW);
00358         else
00359             mPixelRange = mOglWnd->height - (2*cSbW);
00360         SetRange(mScrollRange, mScrollPage);
00361 
00362         if (mScrollRange == mScrollPage){
00363 //            oglSys.ErrorBox("Error", "Division by zero mScrollRange==mScrollPage");
00364             mScrollPage--;// Provisorisch
00365         }
00366         // RvB: Introduced double cast to prevent overflow
00367         mPixelPos = (mPixelRange - mPixelPage) * (double) mScrollPos /
00368                     (mScrollRange - mScrollPage);
00369 
00370         RepositionViewports();
00371 
00372         Window::InitDisplayFunc();
00373     }
00374 
00375     virtual void
00376     DisplayFunc()
00377     {
00378         if (mPagePressed && RepeatTime())
00379             PropagateScrolling();
00380 
00381         Window::DisplayFunc();
00382     }
00383    
00384     void
00385     PropagateScrolling()
00386     {
00387         if (mHorizontal)
00388         {
00389             if (mMouseDownPos - mPixelPos < 0)
00390                 SetNewPos(mScrollPos - mScrollPage);
00391             else
00392                 if(mMouseDownPos - mPixelPos > mPixelPage)
00393                     SetNewPos(mScrollPos + mScrollPage);
00394         }
00395         else
00396         {
00397             if (mMouseDownPos - mPixelRange + mPixelPos < -mPixelPage)
00398                 SetNewPos(mScrollPos + mScrollPage);
00399             else
00400                 if (mMouseDownPos - mPixelRange + mPixelPos > 0)
00401                     SetNewPos(mScrollPos - mScrollPage);
00402         }
00403     }
00404 
00405     void
00406     ButtonSelectionEvent(Button *src, void* vdata)
00407     {
00408         int data = (long long) vdata;
00409         switch (data)
00410         {
00411         case 1: // decrement
00412             SetNewPos(mScrollPos-mScrollLine);
00413             break;
00414         case 3: // increment
00415             SetNewPos(mScrollPos+mScrollLine);
00416             break;
00417         }
00418     }
00419 
00420     virtual void
00421     KeyboardFunc(INT c, int state)
00422     {
00423         Window::KeyboardFunc(c, state);
00424         if (!mMapKeysTarget && mScrollKeyHandling)
00425             ScrollKeys(c, state);
00426     }
00427 
00428     void
00429     ScrollKeys(INT c, int state)
00430     {
00431         if (state & (oglControl|oglAlt))
00432             return;
00433 
00434         switch(c)
00435         {
00436         case oglLEFT:
00437         case oglUP:
00438             ChangePos(-mScrollLine * ((state&oglShift) ? 5 : 1));
00439             break;
00440         case oglDOWN:
00441         case oglRIGHT:
00442             ChangePos(mScrollLine * ((state&oglShift) ? 5 : 1));
00443             break;
00444         case oglPAGEUP:
00445             ChangePos(-mScrollPage);
00446             break;
00447         case oglPAGEDOWN:
00448             ChangePos(mScrollPage);
00449             break;
00450         case oglHOME:
00451             SetNewPos(0);
00452             break;
00453         case oglEND:
00454             SetNewPos(mScrollRange);
00455             break;
00456         }
00457     }
00458 
00459     void SetFixedWide(bool mode)            { mFixedWide = mode; }
00460     bool GetFixedWide()                     { return mFixedWide; }
00461 
00462     class ScrollThumb : public Button
00463     {
00464     public:
00465         ScrollThumb(ScrollBar* parent, int width, int height, std::string label) :
00466             Button(parent, width, height, label)
00467         {
00468             mParent = parent;
00469             SetRoundness(0, 0, 0, 0);
00470             SetBorderType(BEV_ETCHED);
00471             SetBackground(0x0);
00472 #ifdef OGL_USING_GLUT
00473             SetAlignOffsets(0,-1);
00474 #endif
00475         }
00476 
00477         virtual void
00478         MouseFunc(INT msg, INT but, INT state, INT x, INT y)
00479         {
00480             if (!GetState() || (state & (oglShift|oglControl)))
00481                 return;
00482 
00483             Button::MouseFunc(msg, but, state, x, y);
00484             if (msg == oglMouseDown && but == oglLeftButton) 
00485             {
00486                 mDragging = true;
00487                 mClickX = x;
00488                 mClickY = y;
00489             }
00490 
00491             if (msg == oglMouseUp && but == oglLeftButton)
00492                 mDragging = false;
00493             if (msg == oglMouseMove)
00494             {
00495                 if (mDragging)
00496                 {
00497                     if (mParent->mHorizontal)
00498                     {
00499                         mOglWnd->x += x - mClickX;
00500                         // check restraints 
00501                         if (mOglWnd->x < cSbW)
00502                             mOglWnd->x = cSbW;
00503                         int max = mParent->mPixelRange + cSbW - mOglWnd->width;
00504                         if (mOglWnd->x > max)
00505                             mOglWnd->x = max;
00506                         // feedback to parent
00507                         mParent->OnScrollThumb(mOglWnd->x - cSbW);
00508                     }
00509                     else
00510                     {
00511                         mOglWnd->y += y - mClickY;
00512                         // check restraints 
00513                         if (mOglWnd->y < cSbW)
00514                             mOglWnd->y = cSbW;
00515                         int max = mParent->mPixelRange + cSbW - mOglWnd->height;
00516                         if (mOglWnd->y > max)
00517                             mOglWnd->y = max;
00518                         // feedback to parent
00519                         mParent->OnScrollThumb(mParent->mPixelRange + cSbW -
00520                                               mOglWnd->height - mOglWnd->y);
00521                     }
00522                 }
00523             }
00524         }
00525     private:
00526         ScrollBar*  mParent;
00527         bool        mDragging;
00528         int         mClickX;
00529         int         mClickY;
00530     };
00531 
00532 protected:
00533     bool                 mHorizontal;
00534     bool                 mFixedWide;
00535     bool                 mScrollKeyHandling;
00536     ULONG                mOldBorderBg;
00537     int                  mWide;
00538     ScrollBarListener*   mListener;
00539     void*                mListenerData;
00540     DirectionButton*     mButIncr;
00541     DirectionButton*     mButDecr;
00542     ScrollThumb*         mButThumb;
00543     int                  mMouseDownPos;
00544     bool                 mPagePressed;
00545 
00546                          // in 'scroll units' (lines)
00547     int                  mScrollRange, mScrollPage, mScrollPos;
00548     int                  mPixelRange, mPixelPage, mPixelPos; // in pixels
00549     int                  mScrollLine;
00550 
00551     // RvB: Risk division by zero?: mPixelRange==mPixelPage 
00552     void
00553     OnScrollThumb(int pos)
00554     {
00555         mPixelPos = pos;
00556         // RvB: Provisorische oplossing. Met Michiel bespreken
00557         if (mPixelRange == mPixelPage){
00558             //oglSys.ErrorBox("Error", "Division by zero");
00559             mPixelPage--;
00560         }
00561         double p = (double)pos/(double)(mPixelRange-mPixelPage);
00562         mScrollPos = (int) (p * (mScrollRange-mScrollPage));
00563         if(mListener)
00564             mListener->OnScroll(this, mScrollPos, mListenerData);
00565     }
00566 
00567     friend class ScrollThumb;
00568 
00569 
00570 private:
00571     static const int cSbW = 16;
00572 
00573     void
00574     Init(bool isHor, int wide)
00575     {
00576         GuiGeneralName("ScrollBar");
00577         GuiName("ScrollBar");
00578         mHorizontal = isHor;
00579         mScrollKeyHandling = true;
00580         mFixedWide = false;
00581         mWide = wide;
00582         mPixelRange = (isHor ? mOglWnd->width : mOglWnd->height) - (2*cSbW);
00583         mScrollRange = 0;
00584         mScrollPage = 0;
00585         mScrollPos = 0;
00586         mScrollLine = 1;
00587         mPixelPos = 0;
00588         mListener = 0;
00589         mListenerData = 0;
00590         mPagePressed = false;
00591 
00592         mButDecr = new DirectionButton(this, cSbW, cSbW, isHor?2.f:1.f);
00593         mButDecr->GuiName("Decr");
00594         mButDecr->MapKeysTo(this);
00595         mButDecr->SetClosed(false);
00596         mButDecr->SetDirectionFeedback(true);
00597         mButDecr->SetFilled(false);
00598         mButDecr->SetFixedArrowSize(7);
00599 
00600         mButDecr->SetRoundness(0, 0, 0, 0);
00601         mButDecr->SetBorderType(BEV_ETCHED);
00602         mButDecr->SetButtonListener(this, (void*)1);
00603         mButDecr->SetRepeatMode(true);
00604 
00605         mButThumb = new ScrollThumb(this, cSbW, cSbW, "=");
00606         mButThumb->GuiName("Thumb");
00607         mButThumb->MapKeysTo(this);
00608         mButThumb->SetButtonListener(this, (void*)2);
00609         mButThumb->SetShowCancelState(false);
00610 
00611         mButIncr = new DirectionButton(this, cSbW, cSbW, isHor?0.f:3.f);
00612         mButIncr->GuiName("Incr");
00613         mButIncr->MapKeysTo(this);
00614         mButIncr->SetClosed(false);
00615         mButIncr->SetDirectionFeedback(true);
00616         mButIncr->SetFilled(false);
00617         mButIncr->SetFixedArrowSize(7);
00618 
00619         mButIncr->SetButtonListener(this, (void*)3);
00620         mButIncr->SetRepeatMode(true);
00621         mButIncr->SetRoundness(0, 0, 0, 0);
00622         mButIncr->SetBorderType(BEV_ETCHED);
00623         //mButIncr->SetShowCancelState(false);
00624         SetBorderType(BEV_ETCHED);
00625 
00626         SetDisableOGLViewKeys(true);
00627         SetDisableOGLViewMouse(true);
00628     }
00629 };
00630 
00631 } // namespace OglGui
00632 #endif // ScrollBar_h

Generated on Fri Mar 19 09:31:37 2010 for ImpalaSrc by  doxygen 1.5.1