Shaped Bitmap Buttons Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
badams
In need of some credit
In need of some credit
Posts: 3
Joined: Wed Nov 17, 2021 4:35 pm

Shaped Bitmap Buttons

Post by badams »

I want to create multiple bitmap buttons that are close together, so they need to be shaped according to their png file. I have my png files set to 32bpp BGRA format however the alpha layer is clickable and triggers mouse events which is not ideal.

I found a similar thread here: viewtopic.php?f=1&t=38262&sid=1c68f38d6 ... 65e69f2a5f

And I downloaded the shapedtest example that T-Rex posted back in 2014. I incorporated his code that allows him to have shaped bitmap buttons however I ran into some problems.

1. I encounter an error if I try to pass the wxRegion to the SetShape function as a reference. "Initial value of reference to non-const must be Ivalue"
Image
https://pasteboard.co/kLLQO9Wumo90.png

2. If I pass the wxRegion by value I clear the error, however the alpha channel of the bitmap button is still clickable.

Code: Select all

class MyFrame : public wxFrame 
{
public:
    MyFrame();
};

class MyApp : public wxApp
{
    MyFrame* frame = new MyFrame();
    wxImagePanel* drawPane;
public:
    bool OnInit()
    {
        wxInitAllImageHandlers();
        wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
        drawPane = new wxImagePanel(frame, wxT("board321x440.jpg"), wxBITMAP_TYPE_JPEG);
        sizer->Add(drawPane, 1, wxEXPAND);
        frame->SetSizer(sizer);
        frame->SetBackgroundColour(wxColour(192, 192, 192));
        frame->Show();
        return true;
    }
};
DECLARE_APP(MyApp)
IMPLEMENT_APP(MyApp)

class wxBitmappedButton : public wxButton
{
    wxBitmap m_holdOrg;
    wxBitmap m_holdStartHold;
    bool m_IsPushed;
public:
    bool SetShape(wxWindow* victim, wxRegion& region);
    wxBitmappedButton(wxWindow* parent, wxWindowID id, wxBitmap holdOrg, wxBitmap holdStartHold, wxPoint pos);
    DECLARE_EVENT_TABLE()
    void OnMouseDown(wxMouseEvent& event);
    void OnPaint(wxPaintEvent& event);
};
BEGIN_EVENT_TABLE(wxBitmappedButton, wxButton)
EVT_LEFT_DOWN(wxBitmappedButton::OnMouseDown)
EVT_PAINT(wxBitmappedButton::OnPaint)
END_EVENT_TABLE()

wxBitmappedButton::wxBitmappedButton(wxWindow* parent, wxWindowID id, wxBitmap holdOrg, wxBitmap holdStartHold, wxPoint pos) : wxButton(parent, id, wxEmptyString, pos), m_IsPushed(false), m_holdOrg(holdOrg), m_holdStartHold(holdStartHold)
{
    SetSize(m_holdOrg.GetWidth(), m_holdOrg.GetHeight());
    SetShape(this, wxRegion(m_holdOrg)); 
}

void wxBitmappedButton::OnMouseDown(wxMouseEvent& event)
{
    m_IsPushed = true;
    Refresh();
}

void wxBitmappedButton::OnPaint(wxPaintEvent& event)
{
    wxPaintDC dc(this);
    m_IsPushed ? dc.DrawBitmap(m_holdOrg, 0, 0, false):dc.DrawBitmap(m_holdStartHold, 0, 0, false);
}

MyFrame::MyFrame() : wxFrame(NULL, wxID_ANY, "", wxPoint(0, 0), wxSize(800, 480), wxNORESIZE_FRAME_STYLE)
{
    wxImage::AddHandler(new wxPNGHandler);
    wxBitmap holdOrg;
    wxBitmap holdStartHold;

    holdOrg.LoadFile(wxT("holdOrg.png"), wxBITMAP_TYPE_PNG);
    holdStartHold.LoadFile(wxT("holdStartHold.png"), wxBITMAP_TYPE_PNG);
    wxBitmappedButton* btn = new wxBitmappedButton(this, wxID_CLOSE, holdOrg, holdStartHold, wxPoint(0,0));
}

bool wxBitmappedButton::SetShape(wxWindow* victim, wxRegion& region)
{
    DWORD noBytes = ::GetRegionData((HRGN)region.GetHRGN(), 0, NULL);
    RGNDATA* rgnData = (RGNDATA*) new char[noBytes];
    ::GetRegionData((HRGN)region.GetHRGN(), noBytes, rgnData);
    HRGN hrgn = ::ExtCreateRegion(NULL, noBytes, rgnData);
    delete[](char*) rgnData;

    RECT rect;
    DWORD dwStyle = ::GetWindowLong((HWND)victim->GetHandle(), GWL_STYLE);
    DWORD dwExStyle = ::GetWindowLong((HWND)victim->GetHandle(), GWL_EXSTYLE);
    ::GetClientRect((HWND)victim->GetHandle(), &rect);
    ::AdjustWindowRectEx(&rect, dwStyle, FALSE, dwExStyle);
    ::OffsetRgn(hrgn, -rect.left, -rect.top);

    return true;
}
OS is Windows 10
default Visual Studio 2019 C++ compiler
wxWidgets 3.1.5
User avatar
doublemax
Moderator
Moderator
Posts: 19158
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Shaped Bitmap Buttons

Post by doublemax »

Just check if the mouse click is inside the region yourself.

BTW: What is your SetShape() method supposed to do?
Use the source, Luke!
badams
In need of some credit
In need of some credit
Posts: 3
Joined: Wed Nov 17, 2021 4:35 pm

Re: Shaped Bitmap Buttons

Post by badams »

doublemax wrote: Fri Nov 19, 2021 3:56 pm Just check if the mouse click is inside the region yourself.
Thanks for the help doublemax. I am not sure how I could check if the mouse click is inside the region, would you be able to provide a quick example?
doublemax wrote: Fri Nov 19, 2021 3:56 pm BTW: What is your SetShape() method supposed to do?
To be honest I don't know exactly how this method works, I am new to C++ programming and wxWidgets. I found the example shapedtest that I linked to in my original post and this example had the functionality that I desired so I tried to implement it. In this example, Trex doesn't check to see if the mouse event is inside the region so I am assuming that the SetShape method sets the region to opaque pixels and ignores translucent pixels. But again I don't understand the function.
User avatar
doublemax
Moderator
Moderator
Posts: 19158
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Shaped Bitmap Buttons

Post by doublemax »

If you store the region in a member variable:

Code: Select all

void wxBitmappedButton::OnMouseDown(wxMouseEvent& event)
{
  if( m_rgn.Contains( event.GetPosition() ) == wxOutRegion )
  {
    event.Skip();
     return;
  }
  
  m_IsPushed = true;
  Refresh();
}
To be honest I don't know exactly how this method works
Could you test what happens if you don't call SetShape()?

If it actually does something, could you provide complete compilable source code, ideally with the images you're using?
Use the source, Luke!
badams
In need of some credit
In need of some credit
Posts: 3
Joined: Wed Nov 17, 2021 4:35 pm

Re: Shaped Bitmap Buttons

Post by badams »

I was able to create a shaped bitmap button where the opaque portion of the bitmap is clickable and not the transparent pixels around the button.

Here is the repo with an example project.

https://github.com/badams10/ShapedButtonExample

Thank you for the help doublemax.
Post Reply