Page 1 of 1

Modern Custom Button Boostrap-like Theme

Posted: Wed Sep 02, 2020 8:39 am
by qGeorge
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 :)

Re: Modern Custom Button Boostrap-like Theme

Posted: 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