Main Page | Namespace List | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

slidebar.cpp

Go to the documentation of this file.
00001 
00002 // Name:        slidebar.cpp
00003 // Purpose:     wxSlideBar implementation.
00004 // Author:      Mark McCormack
00005 // Modified by:
00006 // Created:     25/05/04
00007 // RCS-ID:      $Id: slidebar.cpp,v 1.9 2005/05/12 14:04:48 frm Exp $
00008 // Copyright:   (c) 2004 Mark McCormack
00009 // Licence:     wxWindows license
00011 
00012 #include <wx/slidebar.h>
00013 #include <wx/barholder.h>
00014 #include <wx/util.h>
00015 
00016 #include <wx/menu.h>
00017 #include <wx/list.h>
00018 #include <wx/listimpl.cpp>
00019 #include <wx/dynarray.h>
00020 #include <wx/arrimpl.cpp>
00021 
00022 using namespace wxUtil;
00023 
00024 enum eContextMenu {
00025     IDM_LOCK_BARS = 200,    // TODO: check ids?
00026     IDM_ITEMS,
00027 };
00028 
00029 #define MINIMUM_HEIGHT 4    // if we are empty, this is our minimum presence
00030 
00031 #define STREAM_VERSION  wxT("wxSlideBar-Stream-v1.0")
00032 
00033 // ----------------------------------------------------------------------------
00034 // wxSlideBar constants & wx-macros
00035 // ----------------------------------------------------------------------------
00036 
00037 BEGIN_EVENT_TABLE( wxSlideBar, wxWindow )
00038     // these two events make the control 'layout aware'
00039     EVT_CALCULATE_LAYOUT( wxSlideBar::OnCalculateLayout )
00040     EVT_QUERY_LAYOUT_INFO( wxSlideBar::OnQueryLayoutInfo )
00041     EVT_CONTEXT_MENU( wxSlideBar::OnContextMenu )
00042     EVT_MENU( IDM_LOCK_BARS, wxSlideBar::OnLockBars )
00043     EVT_SIZE( wxSlideBar::OnSize )
00044 END_EVENT_TABLE()
00045 
00046 DEFINE_EVENT_TYPE( wxEVT_SLIDEBAR_SIZE_CHANGED )
00047 DEFINE_EVENT_TYPE( wxEVT_SLIDEBAR_UPDATE_LAYOUT )
00048 
00049 IMPLEMENT_DYNAMIC_CLASS( wxSlideBar, wxWindow )
00050 
00051 WX_DEFINE_LIST( BarHolderList );
00052 WX_DEFINE_OBJARRAY( BarPlacementArray );
00053 
00054 // ----------------------------------------------------------------------------
00055 // wxSlideBar implementation
00056 // ----------------------------------------------------------------------------
00057 
00058 void wxSlideBar::Init() {
00059     areaHeight_ = 0;
00060     areaWidth_ = 0;
00061     mode_ = wxSLIDE_MODE_SIMPLE;
00062     barList_.Clear();
00063     barLock_ = false;
00064     pContextMenu_ = NULL;
00065 }
00066 
00067 bool wxSlideBar::Create( wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) {
00068     wxASSERT(parent);
00069     // create the wxWindows controls
00070     if( !wxWindow::Create( parent, id, pos, size, style | wxCLIP_CHILDREN, name ) ) {
00071         return FALSE;
00072     }
00073     SetBackgroundColour(GetBackgroundColour()); // XXX: unsure why we have to do this?
00074 
00075     return TRUE;
00076 }
00077 
00078 wxSlideBar::~wxSlideBar() {
00079     // delete context menu
00080     if( pContextMenu_ ) {
00081         delete pContextMenu_;
00082         pContextMenu_ = NULL;
00083     }
00084 }
00085 
00086 void wxSlideBar::OnQueryLayoutInfo( wxQueryLayoutInfoEvent& WXUNUSED(event) ) {
00087     // this is the function that wxLayoutAlgorithm calls to ascertain the window dimensions
00088 }
00089 
00090 void wxSlideBar::OnCalculateLayout( wxCalculateLayoutEvent& event ) {
00091     // check for a 'query only' event
00092     bool queryMode = false;
00093     if( (event.GetFlags() & wxLAYOUT_QUERY) != 0 ) {
00094         queryMode = true;
00095     }
00096 
00097     wxRect areaRect = event.GetRect();
00098     
00099     // position ourselves
00100     int width = areaRect.GetWidth();
00101     int height = 0;
00102     BarPlacementArray & bpl = CalcBarPlacement( width, &height );
00103     if( !queryMode ) {
00104         applyBarPlacement( bpl );
00105         SetSize( areaRect.GetX(), areaRect.GetY(), areaRect.GetWidth(), height );
00106     }
00107 
00108     // chew off a bit of area for ourselves from the layout area
00109     areaRect.SetY( areaRect.GetY() + height );
00110     areaRect.SetHeight( areaRect.GetHeight() - height );
00111     event.SetRect( areaRect );
00112 }
00113 
00114 void wxSlideBar::SetMode( wxSlideBarMode mode ) {
00115     // change mode
00116     mode_ = mode;
00117     UpdateLayout();
00118 }
00119 
00120 wxSlideBarMode wxSlideBar::GetMode() {
00121     return mode_;
00122 }
00123 
00124 void wxSlideBar::SetBarLock( bool enable ) {
00125     // enable/disable bar lock 
00126     barLock_ = enable;
00127 
00128     // for all bars we own
00129     for( BarHolderList::Node *node = barList_.GetFirst(); node; node = node->GetNext() ) {
00130         // get holder & placement
00131         wxBarHolder * pBarHolder = node->GetData();
00132         wxASSERT(pBarHolder);
00133         pBarHolder->ShowGripper( !enable );
00134     }
00135 
00136     UpdateLayout();
00137 }
00138 
00139 bool wxSlideBar::GetBarLock() {
00140     return barLock_;
00141 }
00142 
00143 wxBarHolder * wxSlideBar::AddWindow( wxWindow * pWindow, const wxString & label, unsigned int flags ) {
00144     // add a window as a new bar
00145     wxASSERT(pWindow);
00146 
00147     // create a holder for the window
00148     wxBarHolder * pBarHolder = new wxBarHolder( this, 0 );
00149     pBarHolder->AddWindow( pWindow, label, flags );
00150     pBarHolder->SetSlideBar( this );
00151     wxString key = pBarHolder->GetLabel();
00152     barList_.Append( key, pBarHolder );
00153     UpdateLayout();
00154 
00155     return pBarHolder;
00156 }
00157 
00158 void wxSlideBar::UpdateLayout() {
00159     // create an update event
00160     wxCommandEvent e( wxEVT_SLIDEBAR_UPDATE_LAYOUT );
00161     e.SetEventObject( this );
00162     GetEventHandler()->AddPendingEvent( e );
00163 /*
00164     wxFrame * pFrame = wxDynamicCast( GetParent(), wxFrame );
00165     if( pFrame ) {
00166         pFrame->SendSizeEvent();
00167     }
00168     refreshBars();
00169 */    
00170 }
00171 
00172 void wxSlideBar::DoGetSize( int * x, int * y ) const {
00173     if( x ) *x = areaWidth_;
00174     if( y ) *y = areaHeight_;
00175 }
00176 
00177 wxSize wxSlideBar::DoGetBestSize() const {
00178     return GetSize();
00179 }
00180 
00181 void wxSlideBar::OnSize( wxSizeEvent &event ) {
00182     int oldHeight = areaHeight_;
00183 
00184     // update our height & width
00185     wxSize size = event.GetSize();
00186     areaWidth_ = size.GetWidth();
00187     areaHeight_ = size.GetHeight();
00188 
00189     // generate a size change event?
00190     if( oldHeight != areaHeight_ ) {
00191         // create a size event
00192         wxCommandEvent e( wxEVT_SLIDEBAR_SIZE_CHANGED );
00193         e.SetEventObject( this );
00194         GetEventHandler()->AddPendingEvent( e );
00195     }
00196 }
00197 
00198 void wxSlideBar::OnContextMenu( wxContextMenuEvent &event ) {
00199     // show the context menu
00200     createContextMenu();
00201     wxPoint mp = event.GetPosition();
00202     mp = ScreenToClient( mp );
00203     PopupMenu( pContextMenu_, mp );
00204     deleteContextMenu();
00205 }
00206 
00207 void wxSlideBar::OnLockBars( wxCommandEvent & WXUNUSED(event) ) {
00208     // toggle locking
00209     SetBarLock( GetBarLock() ^ true );
00210 }
00211 
00212 void wxSlideBar::OnContextItem( wxCommandEvent &event ) {
00213     int id = event.GetId();
00214 
00215     // toggle visibility for item
00216     BarHolderList::Node * node = barList_.Item( id - IDM_ITEMS );
00217     wxASSERT(node);
00218     wxBarHolder * pBarHolder = node->GetData();
00219     wxASSERT(pBarHolder);
00220 
00221     bool visible = pBarHolder->IsShown();
00222     pBarHolder->Show( visible ^ true );
00223     
00224     UpdateLayout();
00225 }
00226 
00227 wxBarHolder * wxSlideBar::GetBarHolderAt( BarPlacementArray &barPlacementArray, wxPoint pt ) {
00228     // for all bars in the provided array
00229     for( unsigned int i=0; i<barPlacementArray.GetCount(); i++ ) {
00230         // get holder & placement
00231         wxBarPlacement &pl = barPlacementArray.Item( i );
00232         wxBarHolder * pBarHolder = pl.pBarHolder;
00233         wxASSERT(pBarHolder);
00234         wxRect r = pl.placement;
00235         if( r.Inside( pt ) ) {
00236             return pBarHolder;
00237         }
00238     }
00239 
00240     return NULL;
00241 }
00242 
00243 wxBarHolder * wxSlideBar::GetBarHolderAt( wxPoint pt ) {
00244     // for all bars we own
00245     for( BarHolderList::Node *node = barList_.GetFirst(); node; node = node->GetNext() ) {
00246         // get holder & placement
00247         wxBarHolder * pBarHolder = node->GetData();
00248         wxASSERT(pBarHolder);
00249         if( !pBarHolder->IsShown() ) {
00250             // ignore bar if hidden
00251             continue;
00252         }
00253 
00254         wxRect r = pBarHolder->GetRect();
00255         if( r.Inside( pt ) ) {
00256             return pBarHolder;
00257         }
00258     }
00259 
00260     return NULL;
00261 }
00262 
00263 void wxSlideBar::SwapBarHolders( wxBarHolder * p1, wxBarHolder * p2 ) {
00264     // swaps the position of two bar holders in the holder list
00265     wxASSERT(p1 && p2);
00266     BarHolderList::Node *p1Node = barList_.Find( p1 );
00267     BarHolderList::Node *p2Node = barList_.Find( p2 );
00268     wxASSERT(p1Node && p1Node);
00269     p1Node->SetData( p2 );
00270     p2Node->SetData( p1 );
00271 }
00272 
00273 BarPlacementArray & wxSlideBar::CalcBarPlacement( int width, int * pAreaHeight ) {
00274     barPlacementArray_.Clear();
00275     if( width == -1 ) {
00276         width = GetClientSize().x;
00277     }
00278     if( width == 0 ) {
00279         return barPlacementArray_;
00280     }
00281 
00282     // layout the contained bars
00283     bool finished = false;
00284     int x = 0, y = 0, rowHeight = 0, rowWidth = width;
00285     BarPlacementArray rowHolders;
00286     for( BarHolderList::Node *node = barList_.GetFirst(); node;  ) {
00287         // get holder
00288         wxBarHolder * pBarHolder = node->GetData();
00289         wxASSERT(pBarHolder);
00290 
00291         // is hidden?
00292         if( !pBarHolder->IsShown() ) {
00293             // skip
00294             node = node->GetNext();
00295             if( !node ) {
00296                 finished = true;
00297             }
00298             else
00299                 continue;
00300         }
00301 
00302         // get size
00303         wxSize barSize = pBarHolder->GetBestSize();
00304 
00305         wxBarPlacement barPlacement;
00306         barPlacement.pBarHolder = pBarHolder;
00307         wxRect & r = barPlacement.placement;
00308 
00309         // can we fit the bar on the current row?
00310         bool noFit = false;
00311         if( !finished && (x + barSize.GetWidth() <= width || x == 0) ) {
00312             // yes
00313             r.SetPosition( wxPoint( x, y ) );
00314             r.SetSize( barSize );
00315             rowHolders.Add( barPlacement );
00316             x += barSize.GetWidth();
00317             node = node->GetNext();
00318             if( !node ) {
00319                 finished = true;
00320             }
00321             if( rowHeight < barSize.GetHeight() ) {
00322                 // make row taller
00323                 rowHeight = barSize.GetHeight();
00324             }
00325         }
00326         else {
00327             // no
00328             noFit = true;
00329         }
00330         
00331         // do a 'end-of-row'
00332         if( finished || noFit || (mode_ == wxSLIDE_MODE_SIMPLE)  ) {
00333             for( unsigned int c = 0; c<rowHolders.GetCount(); c++ ) {
00334                 // update bar position for this row
00335                 wxBarPlacement &bp = rowHolders[c];
00336                 wxRect & r = bp.placement;
00337                 int width = (c == (rowHolders.GetCount()-1) ? (rowWidth - r.GetX()) : r.GetWidth() );
00338                 int height = rowHeight;
00339                 r.SetSize( wxSize( width, height ) );
00340 
00341                 // add to final array
00342                 barPlacementArray_.Add( bp );
00343             }
00344 
00345             // start a new row
00346             y += rowHeight;
00347             x = 0;
00348             rowHeight = 0;
00349             rowWidth = width;
00350             rowHolders.Clear();
00351         }
00352     }
00353 
00354     // don't allow zero height
00355     if( y == 0 ) y = MINIMUM_HEIGHT;
00356 
00357     // return new height also?
00358     if( pAreaHeight ) *pAreaHeight = y;
00359 
00360     return barPlacementArray_;
00361 }
00362 
00363 bool wxSlideBar::SaveToStream( wxOutputStream &stream ) {
00364 
00365     // version
00366     WriteString( stream, STREAM_VERSION );
00367 
00368     // attributes
00369     stream.Write( &mode_, sizeof( mode_ ) );
00370     stream.Write( &barLock_, sizeof( barLock_ ) );
00371 
00372     // bars
00373     WriteString( stream, wxT("<layout>") );
00374 
00375     int barCount = barList_.GetCount();
00376     stream.Write( &barCount, sizeof( barCount ) );
00377     for( BarHolderList::Node *node = barList_.GetFirst(); node; node = node->GetNext() ) {
00378         wxBarHolder * pBarHolder = node->GetData();
00379 
00380         // name
00381         WriteString( stream, pBarHolder->GetLabel() );  // TODO: really should be non-visual i.e GetName()
00382 
00383         // visiblity
00384         bool visible = pBarHolder->IsShown();
00385         stream.Write( &visible, sizeof( visible ) );
00386     }
00387 
00388     return true;
00389 }
00390 
00391 bool wxSlideBar::LoadFromStream( wxInputStream &stream ) {
00392 
00393     // version
00394     wxString version = ReadString( stream );
00395     if( version != STREAM_VERSION ) {
00396         return false;
00397     }
00398 
00399     // attributes
00400     stream.Read( &mode_, sizeof( mode_ ) );
00401     bool barLock = false;
00402     stream.Read( &barLock, sizeof( barLock ) );
00403     SetBarLock( barLock );
00404 
00405     wxString layoutTag = ReadString( stream );
00406     if( layoutTag == wxT("<layout>") ) {
00407         // create a copy of the bar list
00408         BarHolderList tmpBarList( wxKEY_STRING );
00409         for( BarHolderList::Node *node = barList_.GetFirst(); node; node = node->GetNext() ) {
00410             wxBarHolder * pBarHolder = node->GetData();
00411             tmpBarList.Append( pBarHolder->GetLabel(), pBarHolder );
00412         }
00413         barList_.Clear();
00414 
00415         // read in windows
00416         int barCount = 0;
00417         stream.Read( &barCount, sizeof( barCount ) );
00418         for( int i=0; i<barCount; i++ ) {
00419             // name
00420             wxString name = ReadString( stream );
00421 
00422             // find bar
00423             BarHolderList::Node * node = tmpBarList.Find( name );
00424             if( !node ) {
00425                 // bar no longer exists
00426                 continue;
00427             }
00428             wxBarHolder * pBarHolder = node->GetData();
00429 
00430             // visibility
00431             bool visible = false;
00432             stream.Read( &visible, sizeof( visible ) );
00433             pBarHolder->Show( visible );
00434 
00435             // add to new list
00436             barList_.Append( name, pBarHolder );
00437         }
00438 
00439     }
00440 
00441     UpdateLayout();
00442 
00443     return true;
00444 }
00445 
00446 bool wxSlideBar::SaveToXML( const wxString& filename ) {
00447     return true;
00448 }
00449 
00450 bool wxSlideBar::LoadFromXML( const wxString& filename ) {
00451     return true;
00452 }
00453 
00454 // ----------------------------------------------------------------------------
00455 
00456 void wxSlideBar::applyBarPlacement( BarPlacementArray & bpl ) {
00457     // apply a list of bar placements
00458     for( unsigned int i=0; i<bpl.GetCount(); i++ ) {
00459         // apply holder
00460         wxBarPlacement &pl = bpl.Item( i );
00461         wxBarHolder * pBarHolder = pl.pBarHolder;
00462         wxASSERT(pBarHolder);
00463         pBarHolder->Move( pl.placement.GetPosition() );
00464         pBarHolder->SetHeightOverride( pl.placement.GetHeight() );
00465         pBarHolder->SetWidthOverride( pl.placement.GetWidth() );
00466         pBarHolder->UpdateSize();
00467     }
00468 }
00469 
00470 void wxSlideBar::createContextMenu() {
00471     wxASSERT(!pContextMenu_);
00472 
00473     // create the context menu
00474     pContextMenu_ = new wxMenu;
00475 
00476     // holders
00477     int c = 0;
00478     for( BarHolderList::Node *node = barList_.GetFirst(); node; node = node->GetNext() ) {
00479         // get holder
00480         wxBarHolder * pBarHolder = node->GetData();
00481         wxASSERT(pBarHolder);
00482         wxString label = pBarHolder->GetLabel();
00483 
00484         // add to list of view toggles?
00485         if( label.Length() > 0 ) {
00486             // add item
00487             int itemId = IDM_ITEMS + c;
00488             pContextMenu_->AppendCheckItem( itemId, label );
00489             
00490             // set current state
00491             bool check = pBarHolder->IsShown();
00492             pContextMenu_->Check( itemId, check );
00493             c++;
00494 
00495             // connect event handler
00496             GetEventHandler()->Connect( itemId, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) &wxSlideBar::OnContextItem );
00497             contextIdEnd_ = itemId;
00498         }
00499     }
00500     contextIdStart_ = IDM_ITEMS;
00501 
00502     // standard items
00503     if( c ) {
00504         pContextMenu_->AppendSeparator();
00505     }
00506     pContextMenu_->AppendCheckItem( IDM_LOCK_BARS, wxT("&Lock the bars") );
00507     pContextMenu_->Check( IDM_LOCK_BARS, barLock_ );
00508 }
00509 
00510 void wxSlideBar::deleteContextMenu() {
00511     wxASSERT(pContextMenu_);
00512     // disconnect dynamic events
00513     for( int i=contextIdStart_; i<=contextIdEnd_; i++ ) {
00514         GetEventHandler()->Disconnect( i );
00515     }
00516     delete pContextMenu_;
00517     pContextMenu_ = NULL;
00518 }
00519 
00520 void wxSlideBar::refreshBars() {
00521     for( BarHolderList::Node *node = barList_.GetFirst(); node; node = node->GetNext() ) {
00522         wxBarHolder * pBarHolder = node->GetData();
00523         pBarHolder->Refresh();
00524     }
00525 }

Generated on Sat May 14 14:54:39 2005 for wxDockIt by  doxygen 1.4.2