wxMenuToolBar - first attempt

If you have a cool piece of software to share, but you are not hosting it officially yet, please dump it in here. If you have code snippets that are useful, please donate!
Post Reply
ak777
Earned a small fee
Earned a small fee
Posts: 20
Joined: Wed Dec 22, 2004 11:07 am

wxMenuToolBar - first attempt

Post by ak777 »

Hi all,

I've created some "stub component", that emulates a menubar, independent from wxFrame. It's my attempt to create a dockable menubar using wxDockIt library, but actually this "component" is independent from this lib. You are all welcome to extend/correct this code, it's my first try to write a wxWidgets component, so please don't be strict to me. :)

It contains two parts - a wxMenuToolButton class (responsible for showing and hiding the menu) and wxMenuToolBar class (responsible for control an array of wxMenuToolButtons).

menutoolbutton.h

Code: Select all

////////////////////////////////////////////////////////////////////////////////
// Name:        menutoolbutton.h                                           //
// Purpose:     wxMenuToolButton class, shows related wxPopupMenu by clicking //
// Author:      Andreas Kaiser, based on pieces of code from mmWX             //
//              and wxDockIt libraries                                        //
// Modified by:                                                               //
// Created:     04/01/05                                                      //
// RCS-ID:                                                                    //
// Copyright:                                                                 //
// Licence:     wxWindows licence                                             //
////////////////////////////////////////////////////////////////////////////////

#ifndef WX_MENUTOOLBUTTON_H
#define WX_MENUTOOLBUTTON_H

// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include <wx/control.h>
#include <wx/dcclient.h>
#include <wx/settings.h>
#include <wx/menu.h>

// ----------------------------------------------------------------------------
// wxMenuToolButton
// ----------------------------------------------------------------------------
class wxMenuToolButton: public wxControl
{
    DECLARE_EVENT_TABLE()
public:
    // Default constructor
    wxMenuToolButton() { 
        Init();
    }

    void Init();
    
    // Normal constructor
    wxMenuToolButton( wxWindow *parent,
                      wxWindowID id,
                      wxString caption,
                      wxMenu* pMenu = NULL,
                      const wxPoint& pos = wxDefaultPosition,
                      const wxSize& size = wxDefaultSize,
                      long style = wxBORDER_NONE,
                      const wxString& name = wxT("") ) {
        Init();
        Create( parent, id, pos, size, style, name );
        m_menu = pMenu;
        SetCaption(caption);
    }
    bool Create( wxWindow *parent,
                 wxWindowID id,
                 const wxPoint& pos = wxDefaultPosition,
                 const wxSize& size = wxDefaultSize,
                 long style = wxBORDER_NONE,
                 const wxString& name = wxT("") );

    virtual ~wxMenuToolButton();
    
    void AttachMenu(wxMenu* pMenu);
    wxString GetCaption() const {return m_caption;}
    void SetCaption(wxString caption);
protected:
    void FindBestSize();
    void OnErase(wxEraseEvent& event);
    void OnPaint(wxPaintEvent& event);
    void OnMouse(wxMouseEvent& event);
    
    bool m_pressed;
    bool m_hovered;
    bool m_menuisopen;
    wxString m_caption;
    wxMenu* m_menu;
private:
    int wholeMargin;
    wxPoint captionpos;
    DECLARE_DYNAMIC_CLASS( wxMenuToolButton )
};


#endif
menutoolbutton.cpp

Code: Select all

////////////////////////////////////////////////////////////////////////////////
// Name:        wxMenuToolButton.cpp                                  //
// Purpose:     wxMenuToolButton implementation.                              //
// Author:      Andreas Kaiser, based on pieces of code from mmWX             //
//              and wxDockIt libraries                                        //
// Modified by:                                                               //
// Created:     01/04/05                                                      //
// RCS-ID:                                                                    //
// Copyright:                                                                 //
// Licence:     wxWindows license                                             //
////////////////////////////////////////////////////////////////////////////////

#include "menutoolbutton.h"

// ----------------------------------------------------------------------------
// wxMenuToolButton implementation
// ----------------------------------------------------------------------------

IMPLEMENT_DYNAMIC_CLASS(wxMenuToolButton, wxControl)

BEGIN_EVENT_TABLE( wxMenuToolButton, wxControl )
    EVT_ERASE_BACKGROUND( wxMenuToolButton::OnErase )
    EVT_PAINT( wxMenuToolButton::OnPaint )
    EVT_MOUSE_EVENTS( wxMenuToolButton::OnMouse)
END_EVENT_TABLE()

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

bool wxMenuToolButton::Create( wxWindow *parent,
                               wxWindowID id,
                               const wxPoint& pos,
                               const wxSize& size,
                               long style,
                               const wxString& name ) {

  // create the controls
  if( !wxControl::Create( parent, id, pos, size, style, wxDefaultValidator, name ) ) {
    return false;
  }
  SetSizeHints(size);
  SetBackgroundColour(parent->GetBackgroundColour());
  return true;
}

wxMenuToolButton::~wxMenuToolButton()
{
}

void wxMenuToolButton::Init() {
  // init.
  wholeMargin = 0;
  m_pressed = false;
  m_hovered = false;
  m_menuisopen = false;
  m_menu = NULL;
  m_caption = "";
  captionpos = wxDefaultPosition;
}

void wxMenuToolButton::AttachMenu(wxMenu* pMenu)
{
  m_menu = pMenu;
}

void wxMenuToolButton::FindBestSize()
{
  wxRect cr = GetClientRect();
  int labw=0,labh=0,ext=0;
  if (m_caption != "")
    GetTextExtent(m_caption,&labw,&labh,&ext);
  labh += ext;
  cr.width = wxMax(cr.width,labw);
  cr.height = labh;
  cr.width += 10;
  cr.height += 4;
  captionpos.x = cr.x + 5;
  captionpos.y = cr.y + 2;
  ((wxWindow*)this)->SetSize(cr.width, cr.height);
  ((wxWindow*)this)->SetAutoLayout(true);
  ((wxWindow*)this)->Layout();
}

void wxMenuToolButton::SetCaption(wxString caption)
{
  m_caption = caption;
  FindBestSize();
}

void wxMenuToolButton::OnErase( wxEraseEvent& event ) {
  // skip erase
}

void wxMenuToolButton::OnPaint( wxPaintEvent& event ) {
    wxPaintDC dc(this);
    wxRect cr = GetClientRect();
    
    dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour(),wxSOLID));
    dc.Clear();
        
    if(m_hovered || m_pressed){
      wxColour raisedColour = wxSystemSettings::GetColour( m_pressed ? wxSYS_COLOUR_3DDKSHADOW : wxSYS_COLOUR_3DHIGHLIGHT );
      wxPen raisedPen( raisedColour, 1, 1 );
      wxColour shadowColour = wxSystemSettings::GetColour( m_pressed ? wxSYS_COLOUR_3DHIGHLIGHT : wxSYS_COLOUR_3DDKSHADOW );
      wxPen shadowPen( shadowColour, 1, 1 );
      cr.width--;
      cr.height--;
      cr.Deflate( wholeMargin, wholeMargin ) ;

      // draw top-left
      dc.SetPen( raisedPen );
      dc.DrawLine( cr.x, cr.y, cr.width, cr.y );
      dc.DrawLine( cr.x, cr.y, cr.x, cr.height );

      // draw bottom-right
      dc.SetPen( shadowPen );
      dc.DrawLine( cr.width, cr.y, cr.width, cr.height+1 );
      dc.DrawLine( cr.x, cr.height, cr.width+1, cr.height );
    }
    if( m_hovered & m_pressed ) cr.Offset( 1, 1 );
    if(m_caption != ""){
      dc.SetFont(GetFont());
      if(m_pressed){
        captionpos.x++;
        captionpos.y++;
      }
      if (IsEnabled())
      {
        dc.SetTextForeground(GetForegroundColour());
        dc.DrawText(m_caption, captionpos.x, captionpos.y);
      }
      else
      {
        dc.SetTextForeground(*wxWHITE);
        dc.DrawText(m_caption, captionpos.x+1, captionpos.y+1);
        dc.SetTextForeground(wxColour(100,100,100));
        dc.DrawText(m_caption, captionpos.x, captionpos.y);
        dc.SetTextForeground(*wxBLACK);
      }
      if(m_pressed){
        captionpos.x--;
        captionpos.y--;
      }
    }
}


void wxMenuToolButton::OnMouse(wxMouseEvent& event)
{
	bool insideofme = GetClientRect().Inside(event.GetPosition().x, event.GetPosition().y);
	if(event.Entering()){
		m_hovered = true;
		m_pressed = false;
		Refresh();
	}
	else if (event.Leaving()){
		m_hovered = false;
		if (HasCapture()) ReleaseMouse();
		Refresh();
	}
	else{
		if (event.LeftDown() || event.LeftDClick()){
		m_pressed = insideofme;
		m_hovered = false;
		Refresh();
	}
	if(m_pressed && !m_menuisopen){
		if((m_menu) && (m_menu->GetMenuItemCount()>0)){
			PopupMenu(m_menu, 0, GetClientSize().y);
			m_menuisopen = true;
			CaptureMouse();
			Refresh();
		}
		else{
			m_pressed = false;
			m_hovered = false;
			Refresh();
		}
	}
	else
		if (HasCapture()) {
			m_menuisopen = false;
			m_hovered = false;
			m_pressed = false;
			Refresh();
			ReleaseMouse();
		}
	}
	event.Skip();
}

menutoolbar.h

Code: Select all

////////////////////////////////////////////////////////////////////////////////
// Name:        menutoolbar.h                                           		//
// Purpose:     wxMenuToolBar class, manages array of wxMenuToolButtons				//
// Author:      Andreas Kaiser, based on pieces of code from mmWX             //
//              and wxDockIt libraries                                        //
// Modified by:                                                               //
// Created:     04/01/05                                                      //
// RCS-ID:                                                                    //
// Copyright:                                                                 //
// Licence:     wxWindows licence                                             //
////////////////////////////////////////////////////////////////////////////////

#ifndef WX_MENUTOOLBAR_H
#define WX_MENUTOOLBAR_H

#include <wx/control.h>
#include <wx/settings.h>
#include "menutoolbutton.h"

WX_DECLARE_LIST(wxMenuToolButton, MenuBarButtons);

// ----------------------------------------------------------------------------
// wxMenuToolBar
// ----------------------------------------------------------------------------
class wxMenuToolBar: public wxControl
{
    DECLARE_EVENT_TABLE()
public:
    // Default constructor
    wxMenuToolBar() { 
        Init();
    }

    void Init();
    
    // Normal constructor
    wxMenuToolBar( wxWindow *parent,
                   wxWindowID id,
                   wxString caption,
                   const wxPoint& pos = wxDefaultPosition,
                   const wxSize& size = wxDefaultSize,
                   long style = wxNO_BORDER | wxWANTS_CHARS	| wxCLIP_CHILDREN,
                   const wxString& name = wxT("menubar") ) {
        Init();
        Create( parent, id, pos, size, style, name );
        SetCaption(caption);
    }
    bool Create( wxWindow *parent,
                 wxWindowID id,
                 const wxPoint& pos = wxDefaultPosition,
                 const wxSize& size = wxDefaultSize,
                 long style = wxBORDER_NONE,
                 const wxString& name = wxT("") );

    virtual ~wxMenuToolBar();
    
    wxString GetCaption() const {return m_caption;}
    void SetCaption(wxString caption) { m_caption = caption;}
    
    void AddMenu(wxWindowID id, wxMenu* pMenu, wxString caption);
    void InsertMenu(wxWindowID id, wxMenu* pMenu, wxString caption, size_t pos);
    void RemoveMenu(size_t pos);
    void Enable(wxWindowID id, bool enable = true);
protected:
    void FindBestSize();
    void OnKey(wxKeyEvent& event);
    void OnMouse(wxMouseEvent& event);
    
    wxString m_caption;
private:
    MenuBarButtons buttons;
    DECLARE_DYNAMIC_CLASS( wxMenuToolBar )
};
#endif
menutoolbar.cpp

Code: Select all

////////////////////////////////////////////////////////////////////////////////
// Name:        menutoolbar.h                                              //
// Purpose:     wxMenuToolBar class, holds an array of wxMenuToolButtons and  //
//              emulates a flat menu bar                                      //
// Author:      Andreas Kaiser, based on pieces of code from mmWX             //
//              and wxDockIt libraries                                        //
// Modified by:                                                               //
// Created:     04/01/05                                                      //
// RCS-ID:                                                                    //
// Copyright:                                                                 //
// Licence:     wxWindows licence                                             //
////////////////////////////////////////////////////////////////////////////////

#include <wx/list.h>
#include <wx/listimpl.cpp>
#include "menutoolbar.h"

// ----------------------------------------------------------------------------
// wxMenuToolBar implementation
// ----------------------------------------------------------------------------

WX_DEFINE_LIST(MenuBarButtons);

IMPLEMENT_DYNAMIC_CLASS(wxMenuToolBar, wxControl)

BEGIN_EVENT_TABLE( wxMenuToolBar, wxControl )
    EVT_KEY_DOWN(wxMenuToolBar::OnKey)
    EVT_CHAR(wxMenuToolBar::OnKey)
    EVT_MOUSE_EVENTS( wxMenuToolBar::OnMouse)
END_EVENT_TABLE()

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

bool wxMenuToolBar::Create( wxWindow *parent,
                            wxWindowID id,
                            const wxPoint& pos,
                            const wxSize& size,
                            long style,
                            const wxString& name ) {

  // create the controls
  if( !wxControl::Create( parent, id, pos, size, style, wxDefaultValidator, name ) ) {
    return false;
  }
  buttons.Clear();
  SetSizeHints(size);
  SetBackgroundColour(parent->GetBackgroundColour());
  return true;
}

wxMenuToolBar::~wxMenuToolBar()
{

}

void wxMenuToolBar::Init() {
  m_caption = "";
}

void wxMenuToolBar::FindBestSize()
{
	wxPoint lastpos(0,0);
	wxSize btnsize;
	for( MenuBarButtons::Node *node = buttons.GetFirst(); node; node = node->GetNext() )
	{
		wxMenuToolButton* pButton = node->GetData();
		wxASSERT(pButton);
		pButton->Move(lastpos);
	 	btnsize = pButton->GetSize();
		lastpos.x += btnsize.GetWidth();
	}
	SetSize(lastpos.x+2, btnsize.y);
}

void wxMenuToolBar::OnKey(wxKeyEvent& event)
{
  event.Skip();
}


void wxMenuToolBar::OnMouse(wxMouseEvent& event)
{
  event.Skip();
}

void wxMenuToolBar::AddMenu(wxWindowID id, wxMenu* pMenu, wxString caption)
{
  wxMenuToolButton* onebtn = new wxMenuToolButton(this, id, caption, pMenu);
  buttons.Append(onebtn);
  FindBestSize();
}

void wxMenuToolBar::InsertMenu(wxWindowID id, wxMenu* pMenu, wxString caption, size_t pos)
{
  wxMenuToolButton* onebtn = new wxMenuToolButton(this, id, caption, pMenu);
  buttons.Insert(pos, onebtn);
  FindBestSize();
}

void wxMenuToolBar::RemoveMenu(size_t pos)
{
  if((buttons.GetCount() > 0) && (buttons.GetCount() > pos)){
    buttons.DeleteNode(buttons.Item(pos));
    FindBestSize();
  }
}

void wxMenuToolBar::Enable(wxWindowID id, bool enable)
{
	wxMenuToolButton* pButton = (wxMenuToolButton*)NULL;
	for( MenuBarButtons::Node *node = buttons.GetFirst(); node; node = node->GetNext() )
	{
		pButton = node->GetData();
		if((pButton) && (pButton->GetId() == id) && (pButton->IsEnabled() != enable)){
			pButton->Enable(enable);
			pButton->Refresh();
			break;
		}
	}
}
It works fine on Windows (sorry, but I'm not so familiar with GTK or Cocoa). This code is based on some code parts of mmWX library and wxDockIt library. At this point, I'll thank all the authors of this libraries.

Howe to use it:

Code: Select all

  
  wxMenu* menu1 = new wxMenu;
  wxMenu* menu2 = new wxMenu;
  wxMenu* menu3 = new wxMenu;

  //menu toolbar
  wxMenuToolBar* menutb = new wxMenuToolBar(this, wxID_ANY, wxT("Main menu"));
  //this - this is an object of type [wxWindow derived class, e.g. wxControl, wxPanel, wxFrame, wxMiniFrame ...]
  m_menutb->AddMenu(ID_MENU1, menu1, wxT("Menu1"));
  m_menutb->AddMenu(ID_MENU2, menu2, wxT("Menu2"));
  m_menutb->AddMenu(ID_MENU3, menu3, wxT("Menu3"));
That's all! I hope it will be useful for somebody.
Avi
Super wx Problem Solver
Super wx Problem Solver
Posts: 398
Joined: Mon Aug 30, 2004 9:27 pm
Location: Tel-Aviv, Israel

Post by Avi »

Thanks for posting! Could you post some screenshot so we have better understanding regarding this control's purpose? :)
ak777
Earned a small fee
Earned a small fee
Posts: 20
Joined: Wed Dec 22, 2004 11:07 am

Post by ak777 »

Avi wrote:Thanks for posting! Could you post some screenshot so we have better understanding regarding this control's purpose? :)
Yes, sure I could, but I don't know how :(
Jorg
Moderator
Moderator
Posts: 3971
Joined: Fri Aug 27, 2004 9:38 pm
Location: Delft, Netherlands
Contact:

Post by Jorg »

I wanted to IM you for this, send me one by email and I will FTP it to the solidsteel site later on.

Regards,
- Jorgen
Forensic Software Engineer
Netherlands Forensic Insitute
http://english.forensischinstituut.nl/
-------------------------------------
Jorg's WasteBucket
http://www.xs4all.nl/~jorgb/wb
ak777
Earned a small fee
Earned a small fee
Posts: 20
Joined: Wed Dec 22, 2004 11:07 am

Post by ak777 »

So, here are the screenshors.

Please note, that I've used the wxDockIt library in this example.

Picture 1:
At the top is the wxMenuToolBar, at the bottom is wxToolBar.
Image

Picture 2:
Now the position of wxMenuToolBar and wxToolBar are swaped.
Image
Post Reply