⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 slidebar.cpp

📁 非常好用的可移植的多平台C/C++源代码编辑器
💻 CPP
字号:
/////////////////////////////////////////////////////////////////////////////
// Name:        slidebar.cpp
// Purpose:     wxSlideBar implementation.
// Author:      Mark McCormack
// Modified by:
// Created:     25/05/04
// RCS-ID:
// Copyright:
// Licence:     wxWindows license
/////////////////////////////////////////////////////////////////////////////

#include <wx/intl.h>
#include <wx/slidebar.h>
#include <wx/barholder.h>
#include <wx/util.h>

#include <wx/menu.h>
#include <wx/list.h>
#include <wx/listimpl.cpp>
#include <wx/dynarray.h>
#include <wx/arrimpl.cpp>

using namespace wxUtil;

enum eContextMenu {
	IDM_LOCK_BARS = 200,	// TODO: check ids?
	IDM_ITEMS,
};

#define MINIMUM_HEIGHT 4    // if we are empty, this is our minimum presence

#define STREAM_VERSION  wxT("wxSlideBar-Stream-v1.0")

// ----------------------------------------------------------------------------
// wxSlideBar constants & wx-macros
// ----------------------------------------------------------------------------

BEGIN_EVENT_TABLE( wxSlideBar, wxWindow )
    // these two events make the control 'layout aware'
    EVT_CALCULATE_LAYOUT( wxSlideBar::OnCalculateLayout )
    EVT_QUERY_LAYOUT_INFO( wxSlideBar::OnQueryLayoutInfo )
	EVT_CONTEXT_MENU( wxSlideBar::OnContextMenu )
	EVT_MENU( IDM_LOCK_BARS, wxSlideBar::OnLockBars )
    EVT_SIZE( wxSlideBar::OnSize )
END_EVENT_TABLE()

DEFINE_LOCAL_EVENT_TYPE( wxEVT_SLIDEBAR_SIZE_CHANGED )
DEFINE_LOCAL_EVENT_TYPE( wxEVT_SLIDEBAR_UPDATE_LAYOUT )

IMPLEMENT_DYNAMIC_CLASS( wxSlideBar, wxWindow )

WX_DEFINE_LIST( BarHolderList );
WX_DEFINE_OBJARRAY( BarPlacementArray );

// ----------------------------------------------------------------------------
// wxSlideBar implementation
// ----------------------------------------------------------------------------

void wxSlideBar::Init() {
    areaHeight_ = 0;
    areaWidth_ = 0;
    mode_ = wxSLIDE_MODE_SIMPLE;
    barList_.Clear();
	barLock_ = false;
	pContextMenu_ = NULL;
}

bool wxSlideBar::Create( wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) {
    wxASSERT(parent);
    // create the wxWindows controls
    if( !wxWindow::Create( parent, id, pos, size, style | wxCLIP_CHILDREN, name ) ) {
        return FALSE;
    }
    SetBackgroundColour(GetBackgroundColour()); // XXX: unsure why we have to do this?

    return TRUE;
}

wxSlideBar::~wxSlideBar() {
	// delete context menu
	if( pContextMenu_ ) {
		delete pContextMenu_;
		pContextMenu_ = NULL;
	}
}

void wxSlideBar::OnQueryLayoutInfo( wxQueryLayoutInfoEvent& WXUNUSED(event) ) {
    // this is the function that wxLayoutAlgorithm calls to ascertain the window dimensions
}

void wxSlideBar::OnCalculateLayout( wxCalculateLayoutEvent& event ) {
	// check for a 'query only' event
	bool queryMode = false;
	if( (event.GetFlags() & wxLAYOUT_QUERY) != 0 ) {
		queryMode = true;
	}

    wxRect areaRect = event.GetRect();

	// position ourselves
    int width = areaRect.GetWidth();
    int height = 0;
	BarPlacementArray & bpl = CalcBarPlacement( width, &height );
    if( !queryMode ) {
        applyBarPlacement( bpl );
        SetSize( areaRect.GetX(), areaRect.GetY(), areaRect.GetWidth(), height );
    }

	// chew off a bit of area for ourselves from the layout area
    areaRect.SetY( areaRect.GetY() + height );
    areaRect.SetHeight( areaRect.GetHeight() - height );
    event.SetRect( areaRect );
}

void wxSlideBar::SetMode( eSlideBarMode mode ) {
	// change mode
    mode_ = mode;
    UpdateLayout();
}

eSlideBarMode wxSlideBar::GetMode() {
    return mode_;
}

void wxSlideBar::SetBarLock( bool enable ) {
	// enable/disable bar lock
	barLock_ = enable;

    // for all bars we own
    for( BarHolderList::Node *node = barList_.GetFirst(); node; node = node->GetNext() ) {
        // get holder & placement
        wxBarHolder * pBarHolder = node->GetData();
        wxASSERT(pBarHolder);
		pBarHolder->ShowGripper( !enable );
	}

	UpdateLayout();
}

bool wxSlideBar::GetBarLock() {
	return barLock_;
}

wxBarHolder * wxSlideBar::AddWindow( wxWindow * pWindow, const wxString & label, unsigned int flags ) {
    // add a window as a new bar
    wxASSERT(pWindow);

    // create a holder for the window
    wxBarHolder * pBarHolder = new wxBarHolder( this, 0 );
    pBarHolder->AddWindow( pWindow, label, flags );
    pBarHolder->SetSlideBar( this );
    wxString key = pBarHolder->GetLabel();
    barList_.Append( key, pBarHolder );
    UpdateLayout();

	return pBarHolder;
}

void wxSlideBar::UpdateLayout() {
	// create an update event
	wxCommandEvent e( wxEVT_SLIDEBAR_UPDATE_LAYOUT );
	e.SetEventObject( this );
	GetEventHandler()->AddPendingEvent( e );
/*
    wxFrame * pFrame = wxDynamicCast( GetParent(), wxFrame );
    if( pFrame ) {
        pFrame->SendSizeEvent();
    }
    refreshBars();
*/
}

void wxSlideBar::DoGetSize( int * x, int * y ) const {
    if( x ) *x = areaWidth_;
    if( y ) *y = areaHeight_;
}

wxSize wxSlideBar::DoGetBestSize() const {
    return GetSize();
}

void wxSlideBar::OnSize( wxSizeEvent &event ) {
    int oldHeight = areaHeight_;

	// update our height & width
    wxSize size = event.GetSize();
    areaWidth_ = size.GetWidth();
    areaHeight_ = size.GetHeight();

	// generate a size change event?
    if( oldHeight != areaHeight_ ) {
        // create a size event
        wxCommandEvent e( wxEVT_SLIDEBAR_SIZE_CHANGED );
        e.SetEventObject( this );
        GetEventHandler()->AddPendingEvent( e );
    }
}

void wxSlideBar::OnContextMenu( wxContextMenuEvent &event ) {
	// show the context menu
	createContextMenu();
	wxPoint mp = event.GetPosition();
	mp = ScreenToClient( mp );
	PopupMenu( pContextMenu_, mp );
	deleteContextMenu();
}

void wxSlideBar::OnLockBars( wxCommandEvent & WXUNUSED(event) ) {
	// toggle locking
	SetBarLock( GetBarLock() ^ true );
}

void wxSlideBar::OnContextItem( wxCommandEvent &event ) {
	int id = event.GetId();

	// toggle visibility for item
	BarHolderList::Node * node = barList_.Item( id - IDM_ITEMS );
    wxASSERT(node);
    wxBarHolder * pBarHolder = node->GetData();
    wxASSERT(pBarHolder);

	bool visible = pBarHolder->IsShown();
	pBarHolder->Show( visible ^ true );

    UpdateLayout();
}

wxBarHolder * wxSlideBar::GetBarHolderAt( BarPlacementArray &barPlacementArray, wxPoint pt ) {
    // for all bars in the provided array
    for( unsigned int i=0; i<barPlacementArray.GetCount(); i++ ) {
        // get holder & placement
        strBarPlacement &pl = barPlacementArray.Item( i );
		wxBarHolder * pBarHolder = pl.pBarHolder;
        wxASSERT(pBarHolder);
        wxRect r = pl.placement;
        if( r.Inside( pt ) ) {
            return pBarHolder;
        }
    }

    return NULL;
}

wxBarHolder * wxSlideBar::GetBarHolderAt( wxPoint pt ) {
    // for all bars we own
    for( BarHolderList::Node *node = barList_.GetFirst(); node; node = node->GetNext() ) {
        // get holder & placement
        wxBarHolder * pBarHolder = node->GetData();
        wxASSERT(pBarHolder);
        if( !pBarHolder->IsShown() ) {
            // ignore bar if hidden
            continue;
        }

        wxRect r = pBarHolder->GetRect();
        if( r.Inside( pt ) ) {
            return pBarHolder;
        }
    }

    return NULL;
}

void wxSlideBar::SwapBarHolders( wxBarHolder * p1, wxBarHolder * p2 ) {
    // swaps the position of two bar holders in the holder list
    wxASSERT(p1 && p2);
    BarHolderList::Node *p1Node = barList_.Find( p1 );
    BarHolderList::Node *p2Node = barList_.Find( p2 );
    wxASSERT(p1Node && p1Node);
    p1Node->SetData( p2 );
    p2Node->SetData( p1 );
}

BarPlacementArray & wxSlideBar::CalcBarPlacement( int width, int * pAreaHeight ) {
	barPlacementArray_.Clear();
    if( width == -1 ) {
        width = GetClientSize().x;
    }
    if( width == 0 ) {
        return barPlacementArray_;
    }

	// layout the contained bars
    bool finished = false;
    int x = 0, y = 0, rowHeight = 0, rowWidth = width;
    BarPlacementArray rowHolders;
    for( BarHolderList::Node *node = barList_.GetFirst(); node;  ) {
        // get holder
        wxBarHolder * pBarHolder = node->GetData();
        wxASSERT(pBarHolder);

		// is hidden?
		if( !pBarHolder->IsShown() ) {
			// skip
			node = node->GetNext();
            if( !node ) {
                finished = true;
            }
			else
				continue;
		}

		// get size
        wxSize barSize = pBarHolder->GetBestSize();

		strBarPlacement barPlacement;
		barPlacement.pBarHolder = pBarHolder;
		wxRect & r = barPlacement.placement;

		// can we fit the bar on the current row?
        bool noFit = false;
        if( !finished && (x + barSize.GetWidth() <= width || x == 0) ) {
            // yes
			r.SetPosition( wxPoint( x, y ) );
			r.SetSize( barSize );
            rowHolders.Add( barPlacement );
            x += barSize.GetWidth();
            node = node->GetNext();
            if( !node ) {
                finished = true;
            }
            if( rowHeight < barSize.GetHeight() ) {
                // make row taller
                rowHeight = barSize.GetHeight();
            }
        }
        else {
            // no
            noFit = true;
        }

        // do a 'end-of-row'
        if( finished || noFit || (mode_ == wxSLIDE_MODE_SIMPLE)  ) {
            for( unsigned int c = 0; c<rowHolders.GetCount(); c++ ) {
				// update bar position for this row
                strBarPlacement &bp = rowHolders[c];
				wxRect & r = bp.placement;
				int width = (c == (rowHolders.GetCount()-1) ? (rowWidth - r.GetX()) : r.GetWidth() );
				int height = rowHeight;
				r.SetSize( wxSize( width, height ) );

				// add to final array
				barPlacementArray_.Add( bp );
            }

			// start a new row
            y += rowHeight;
            x = 0;
            rowHeight = 0;
            rowWidth = width;
            rowHolders.Clear();
        }
    }

	// don't allow zero height
	if( y == 0 ) y = MINIMUM_HEIGHT;

    // return new height also?
    if( pAreaHeight ) *pAreaHeight = y;

	return barPlacementArray_;
}

bool wxSlideBar::SaveToStream( wxOutputStream &stream ) {

    // version
    WriteString( stream, STREAM_VERSION );

    // attributes
    stream.Write( &mode_, sizeof( mode_ ) );
    stream.Write( &barLock_, sizeof( barLock_ ) );

    // bars
    WriteString( stream, wxT("<layout>") );

    int barCount = barList_.GetCount();
    stream.Write( &barCount, sizeof( barCount ) );
    for( BarHolderList::Node *node = barList_.GetFirst(); node; node = node->GetNext() ) {
        wxBarHolder * pBarHolder = node->GetData();

        // name
        WriteString( stream, pBarHolder->GetLabel() );  // TODO: really should be non-visual i.e GetName()

        // visiblity
        bool visible = pBarHolder->IsShown();
        stream.Write( &visible, sizeof( visible ) );
    }

    return true;
}

bool wxSlideBar::LoadFromStream( wxInputStream &stream ) {

    // version
    wxString version = ReadString( stream );
    if( version != STREAM_VERSION ) {
        return false;
    }

    // attributes
    stream.Read( &mode_, sizeof( mode_ ) );
    bool barLock = false;
    stream.Read( &barLock, sizeof( barLock ) );
    SetBarLock( barLock );

    wxString layoutTag = ReadString( stream );
    if( layoutTag == wxT("<layout>") ) {
        // create a copy of the bar list
        BarHolderList tmpBarList( wxKEY_STRING );
        for( BarHolderList::Node *node = barList_.GetFirst(); node; node = node->GetNext() ) {
            wxBarHolder * pBarHolder = node->GetData();
            tmpBarList.Append( pBarHolder->GetLabel(), pBarHolder );
        }
        barList_.Clear();

        // read in windows
        int barCount = 0;
        stream.Read( &barCount, sizeof( barCount ) );
        for( int i=0; i<barCount; i++ ) {
            // name
            wxString name = ReadString( stream );

            // find bar
            BarHolderList::Node * node = tmpBarList.Find( name );
            if( !node ) {
                // bar no longer exists
                continue;
            }
            wxBarHolder * pBarHolder = node->GetData();

            // visibility
            bool visible = false;
            stream.Read( &visible, sizeof( visible ) );
            pBarHolder->Show( visible );

            // add to new list
            barList_.Append( name, pBarHolder );
        }

    }

    UpdateLayout();

    return true;
}

// ----------------------------------------------------------------------------

void wxSlideBar::applyBarPlacement( BarPlacementArray & bpl ) {
	// apply a list of bar placements
    for( unsigned int i=0; i<bpl.GetCount(); i++ ) {
        // apply holder
		strBarPlacement &pl = bpl.Item( i );
        wxBarHolder * pBarHolder = pl.pBarHolder;
        wxASSERT(pBarHolder);
		pBarHolder->Move( pl.placement.GetPosition() );
		pBarHolder->SetHeightOverride( pl.placement.GetHeight() );
		pBarHolder->SetWidthOverride( pl.placement.GetWidth() );
		pBarHolder->UpdateSize();
	}
}

void wxSlideBar::createContextMenu() {
	wxASSERT(!pContextMenu_);

	// create the context menu
	pContextMenu_ = new wxMenu;

	// holders
	int c = 0;
    for( BarHolderList::Node *node = barList_.GetFirst(); node; node = node->GetNext() ) {
        // get holder
        wxBarHolder * pBarHolder = node->GetData();
        wxASSERT(pBarHolder);
		wxString label = pBarHolder->GetLabel();

		// add to list of view toggles?
		if( label.Length() > 0 ) {
			// add item
			int itemId = IDM_ITEMS + c;
			pContextMenu_->AppendCheckItem( itemId, label );

			// set current state
			bool check = pBarHolder->IsShown();
			pContextMenu_->Check( itemId, check );
			c++;

			// connect event handler
			GetEventHandler()->Connect( itemId, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) &wxSlideBar::OnContextItem );
			contextIdEnd_ = itemId;
		}
	}
	contextIdStart_ = IDM_ITEMS;

	// standard items
	if( c ) {
		pContextMenu_->AppendSeparator();
	}
	pContextMenu_->AppendCheckItem( IDM_LOCK_BARS, _("&Lock the bars") );
	pContextMenu_->Check( IDM_LOCK_BARS, barLock_ );
}

void wxSlideBar::deleteContextMenu() {
	wxASSERT(pContextMenu_);
	// disconnect dynamic events
	for( int i=contextIdStart_; i<=contextIdEnd_; i++ ) {
		GetEventHandler()->Disconnect( i );
	}
	delete pContextMenu_;
	pContextMenu_ = NULL;
}

void wxSlideBar::refreshBars() {
    for( BarHolderList::Node *node = barList_.GetFirst(); node; node = node->GetNext() ) {
        wxBarHolder * pBarHolder = node->GetData();
        pBarHolder->Refresh();
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -