Modern Custom Button Boostrap-like Theme

Do you like to promote your wxWidgets based application or component!? Post it here and let's see what the critics have to say. Also, if you found that ONE wx component the world needs to know about, put it here for future reference.
Post Reply
qGeorge
In need of some credit
In need of some credit
Posts: 4
Joined: Wed Sep 02, 2020 8:24 am

Modern Custom Button Boostrap-like Theme

Post by qGeorge » Wed Sep 02, 2020 8:39 am

Hello, can someone give me review is this stable and could this be used in commercial applications

Code: Select all

//ModernButton.h
#pragma once

#include <wx/wx.h>


class ModernButton : public wxWindow {

public:
	enum class Type {
		primary,
		danger
	};
	ModernButton(
		Type type,
		wxWindow* parent,
		wxWindowID id,
		const wxString& label = wxEmptyString,
		const wxPoint& pos = wxDefaultPosition,
		const wxSize& size = wxDefaultSize,
		long style = 0,
		const wxString& name = wxASCII_STR(wxPanelNameStr)) : m_type(type),
															  m_text(label),
															  m_focus(false),
															  m_hover(false),
															  wxWindow(parent, id, pos, size, style, name) {

		Bind(wxEVT_MOTION, &ModernButton::mouse_moved, this);
		Bind(wxEVT_LEAVE_WINDOW, &ModernButton::mouse_left_window, this);
		Bind(wxEVT_LEFT_DOWN, &ModernButton::mouse_left_down, this);

		Bind(wxEVT_SET_FOCUS, &ModernButton::set_focus, this);
		Bind(wxEVT_KILL_FOCUS, &ModernButton::kill_focus, this);
		Bind(wxEVT_CHAR_HOOK, &ModernButton::process_enter, this);

		Bind(wxEVT_PAINT, &ModernButton::paint_event, this);

		SetCursor(wxCursor(wxCURSOR_HAND));
	}

private:
	bool m_hover;
	bool m_focus;
	wxString m_text;
	Type m_type;

	void paint_event(wxPaintEvent&) {
		wxPaintDC dc(this);
		render(dc);
	}

	void paint_now() {
		wxClientDC dc(this);
		render(dc);
	}

	void render(wxDC& dc) {

		wxColour color = wxColour(255, 255, 255);
		wxColour background_color;
		wxColour background_color_hover;
		wxColour border_color;

		switch(m_type) {
			case Type::primary: {
				background_color = wxColour(0, 123, 255);
				background_color_hover = wxColour(0, 105, 217);
				border_color = wxColour(63, 72, 204);
			} break;
			case Type::danger: {
				background_color = wxColour(235, 0, 0);
				background_color_hover = wxColour(225, 0, 0);
				border_color = wxColour(200, 0, 0);
			} break;
		}

		if(m_hover || m_focus) {
			dc.SetBrush(wxBrush(background_color_hover));
		} else {
			dc.SetBrush(wxBrush(background_color));
		}

		
		auto text_size = dc.GetTextExtent(m_text);
		int text_width = text_size.GetWidth();
		int text_height = text_size.GetHeight() - 2;

		auto button_width = GetSize().GetWidth();
		auto button_height = GetSize().GetHeight();

		dc.SetPen(wxPen(border_color));
		dc.DrawRectangle(0, 0, button_width, button_height);
		dc.SetTextForeground(color);
		dc.DrawText(m_text, (button_width - text_width) / 2, (button_height - text_height) / 2);
	}

	void mouse_moved(wxMouseEvent&) {
		if(!m_hover) {
			m_hover = true;
			paint_now();
		}
	}

	void mouse_left_window(wxMouseEvent&) {
		if(m_hover) {
			m_hover = false;
			paint_now();
		}
	}

	void mouse_left_down(wxMouseEvent&) {
		wxCommandEvent event(wxEVT_BUTTON, wxID_ANY);
		event.SetEventObject(this);
		AddPendingEvent(event);
	}

	void set_focus(wxFocusEvent&) {
		if(!m_focus) {
			m_focus = true;
			paint_now();
		}
	}

	void kill_focus(wxFocusEvent&) {
		if(m_focus) {
			m_focus = false;
			paint_now();
		}
	}

	void process_enter(wxKeyEvent& e) {
		if(m_focus && e.GetKeyCode() == WXK_RETURN) { 
			wxCommandEvent event(wxEVT_LEFT_DOWN, wxID_ANY);
			wxPostEvent(GetEventHandler(), event);
		}
		e.Skip();
	}
};
and usage

Code: Select all

//NOTE: you need to declare button size
auto button = new ModernButton(ModernButton::Type::primary, this, wxID_ANY, "wxWidgets", wxDefaultPosition, wxSize(90, 24));

Any critics are welcome. Thanks :)

User avatar
[email protected]
In need of some credit
In need of some credit
Posts: 8
Joined: Wed Jul 29, 2020 6:06 pm

Re: Modern Custom Button Boostrap-like Theme

Post by [email protected] » Wed Sep 02, 2020 11:37 am

I haven't tried to run the code yet, but at the very least you should add a "best size" calculation. This is important if users want to use that control in a sizer based layout. For that you should override and implement wxWindow::DoGetBestClientSize
https://docs.wxwidgets.org/trunk/classw ... 3e3d02ee89

Post Reply