Start adding themed buttons.

This commit is contained in:
jmsgrogan 2023-01-18 10:47:13 +00:00
parent dfbc87cb09
commit 942cc2539c
18 changed files with 781 additions and 173 deletions

View file

@ -9,13 +9,12 @@
#include "MouseEvent.h"
#include "FileLogger.h"
Button::Button()
Button::Button(ButtonData::Component component)
: Widget(),
mLabel(),
mCachedColor(ThemeToken::SystemToken::Primary),
mClickedColor(ThemeToken::SystemToken::Secondary),
mClickFunc()
{
mStyle.mComponent = component;
mName = "Button";
}
@ -24,9 +23,9 @@ Button::~Button()
}
std::unique_ptr<Button> Button::Create()
std::unique_ptr<Button> Button::Create(ButtonData::Component component)
{
return std::make_unique<Button>();
return std::make_unique<Button>(component);
}
void Button::setOnClickFunction(clickFunc func)
@ -48,8 +47,8 @@ void Button::onMyMouseEvent(const MouseEvent* event)
MLOG_INFO("Widget mouse event");
if(event->getAction() == MouseEvent::Action::Pressed)
{
mCachedColor = mBackground;
setBackground(mClickedColor);
mStyle.mState = ButtonData::State::Pressed;
setBackground(mStyle.getContainerColor());
if(mClickFunc)
{
mClickFunc(this);
@ -57,7 +56,8 @@ void Button::onMyMouseEvent(const MouseEvent* event)
}
else if(event->getAction() == MouseEvent::Action::Released)
{
setBackground(mCachedColor);
mStyle.mState = ButtonData::State::Enabled;
setBackground(mStyle.getContainerColor());
}
}

View file

@ -1,5 +1,6 @@
#pragma once
#include "ButtonData.h"
#include "Widget.h"
#include "Color.h"
@ -15,11 +16,11 @@ class Button : public Widget
public:
using clickFunc = std::function<void(Widget* self)>;
Button();
Button(ButtonData::Component component = ButtonData::Component::Elevated);
~Button();
static std::unique_ptr<Button> Create();
static std::unique_ptr<Button> Create(ButtonData::Component component = ButtonData::Component::Elevated);
void setLabel(const std::string& text);
@ -34,10 +35,10 @@ protected:
void updateLabel(const PaintEvent* event);
private:
ButtonData mStyle;
std::string mLabel;
clickFunc mClickFunc;
ThemeToken::SystemToken mCachedColor;
ThemeToken::SystemToken mClickedColor;
std::unique_ptr<TextNode> mTextNode;
bool mContentDirty{true};

View file

@ -0,0 +1,347 @@
#include "ButtonData.h"
#include "OpacityTokens.h"
const float ButtonData::DEFAULT_CONTAINER_OPACITY = 1;
const std::unordered_map<ButtonData::ComponentState, Theme::Sys::Color> ButtonData::mContainerColors = {
{{Component::Elevated, State::Enabled}, Theme::Sys::Color::Surface},
{{Component::Elevated, State::Disabled}, Theme::Sys::Color::On_Surface},
{{Component::Elevated, State::Hovered}, Theme::Sys::Color::Primary},
{{Component::Elevated, State::Focused}, Theme::Sys::Color::Primary},
{{Component::Elevated, State::Pressed}, Theme::Sys::Color::Primary},
{{Component::Filled, State::Enabled}, Theme::Sys::Color::Primary},
{{Component::Filled, State::Disabled}, Theme::Sys::Color::On_Surface},
{{Component::Filled, State::Hovered}, Theme::Sys::Color::On_Primary},
{{Component::Filled, State::Focused}, Theme::Sys::Color::On_Primary},
{{Component::Filled, State::Pressed}, Theme::Sys::Color::On_Primary},
};
const std::unordered_map<ButtonData::ComponentState, Theme::Sys::Color> ButtonData::mContainerShadowColors = {
{{Component::Elevated, State::Enabled}, Theme::Sys::Color::Shadow},
{{Component::Filled, State::Enabled}, Theme::Sys::Color::Shadow},
};
const std::unordered_map<ButtonData::ComponentState, Theme::Sys::Elevation> ButtonData::mContainerElevations = {
{{Component::Elevated, State::Enabled}, Theme::Sys::Elevation::Level_1},
{{Component::Elevated, State::Disabled}, Theme::Sys::Elevation::Level_0},
{{Component::Elevated, State::Hovered}, Theme::Sys::Elevation::Level_2},
{{Component::Elevated, State::Focused}, Theme::Sys::Elevation::Level_1},
{{Component::Filled, State::Enabled}, Theme::Sys::Elevation::Level_0},
{{Component::Filled, State::Disabled}, Theme::Sys::Elevation::Level_0},
{{Component::Filled, State::Hovered}, Theme::Sys::Elevation::Level_1},
{{Component::Filled, State::Focused}, Theme::Sys::Elevation::Level_0},
{{Component::Filled, State::Pressed}, Theme::Sys::Elevation::Level_0},
};
const std::unordered_map<ButtonData::ComponentState, float> ButtonData::mContainerOpacity = {
{{Component::Elevated, State::Disabled}, 0.12},
{{Component::Elevated, State::Hovered}, OpacityTokens::getValue(Theme::Sys::StateLayerOpacity::State::Hover)},
{{Component::Elevated, State::Focused}, OpacityTokens::getValue(Theme::Sys::StateLayerOpacity::State::Focus)},
{{Component::Elevated, State::Pressed}, OpacityTokens::getValue(Theme::Sys::StateLayerOpacity::State::Pressed)},
{{Component::Filled, State::Disabled}, 0.12},
{{Component::Filled, State::Hovered}, OpacityTokens::getValue(Theme::Sys::StateLayerOpacity::State::Hover)},
{{Component::Filled, State::Focused}, OpacityTokens::getValue(Theme::Sys::StateLayerOpacity::State::Focus)},
{{Component::Filled, State::Pressed}, OpacityTokens::getValue(Theme::Sys::StateLayerOpacity::State::Pressed)},
};
const std::unordered_map<ButtonData::ComponentState, Theme::Sys::Color> ButtonData::mLabelTextColors = {
{{Component::Elevated, State::Enabled}, Theme::Sys::Color::Primary},
{{Component::Elevated, State::Disabled}, Theme::Sys::Color::On_Surface},
{{Component::Elevated, State::Hovered}, Theme::Sys::Color::Primary},
{{Component::Elevated, State::Focused}, Theme::Sys::Color::Primary},
{{Component::Elevated, State::Pressed}, Theme::Sys::Color::Primary},
{{Component::Filled, State::Enabled}, Theme::Sys::Color::On_Primary},
{{Component::Filled, State::Disabled}, Theme::Sys::Color::On_Surface},
{{Component::Filled, State::Hovered}, Theme::Sys::Color::On_Primary},
{{Component::Filled, State::Focused}, Theme::Sys::Color::On_Primary},
{{Component::Filled, State::Pressed}, Theme::Sys::Color::On_Primary},
};
const std::unordered_map<ButtonData::ComponentState, Theme::Sys::Typescale> ButtonData::mLabelTypescales = {
{{Component::Elevated, State::Enabled}, Theme::Sys::Typescale::Label_Large},
{{Component::Filled, State::Enabled}, Theme::Sys::Typescale::Label_Large},
};
const std::unordered_map<ButtonData::ComponentState, float> ButtonData::mLabelTextOpacity = {
{{Component::Elevated, State::Disabled}, 0.38},
{{Component::Filled, State::Disabled}, 0.38},
};
const std::unordered_map<ButtonData::ComponentState, Theme::Sys::Color> ButtonData::mIconColors = {
{{Component::Elevated, State::Enabled}, Theme::Sys::Color::Primary},
{{Component::Elevated, State::Disabled}, Theme::Sys::Color::On_Surface},
{{Component::Elevated, State::Hovered}, Theme::Sys::Color::Primary},
{{Component::Elevated, State::Focused}, Theme::Sys::Color::Primary},
{{Component::Elevated, State::Pressed}, Theme::Sys::Color::Primary},
{{Component::Filled, State::Enabled}, Theme::Sys::Color::On_Primary},
{{Component::Filled, State::Disabled}, Theme::Sys::Color::On_Surface},
{{Component::Filled, State::Hovered}, Theme::Sys::Color::On_Primary},
{{Component::Filled, State::Focused}, Theme::Sys::Color::On_Primary},
{{Component::Filled, State::Pressed}, Theme::Sys::Color::On_Primary},
};
const std::unordered_map<ButtonData::ComponentState, float> ButtonData::mIconOpacity = {
{{Component::Elevated, State::Disabled}, 0.38},
{{Component::Filled, State::Disabled}, 0.38},
};
Theme::Sys::Color ButtonData::getContainerColor() const
{
if (auto iter = mContainerColors.find(std::make_pair(mComponent, mState)); iter != mContainerColors.end())
{
return iter->second;
}
else
{
if (mState == State::Enabled)
{
return DEFAULT_CONTAINER_COLOR;
}
else if (auto iter = mContainerColors.find(std::make_pair(mComponent, State::Enabled)); iter != mContainerColors.end())
{
return iter->second;
}
else
{
return DEFAULT_CONTAINER_COLOR;
}
}
}
Theme::Sys::Color ButtonData::getContainerShadowColor() const
{
if (auto iter = mContainerShadowColors.find(std::make_pair(mComponent, mState)); iter != mContainerShadowColors.end())
{
return iter->second;
}
else
{
if (mState == State::Enabled)
{
return DEFAULT_CONTAINER_SHADOW_COLOR;
}
else if (auto iter = mContainerShadowColors.find(std::make_pair(mComponent, State::Enabled)); iter != mContainerShadowColors.end())
{
return iter->second;
}
else
{
return DEFAULT_CONTAINER_SHADOW_COLOR;
}
}
}
Theme::Sys::Color ButtonData::getContainerSurfaceTintColor() const
{
switch (mComponent)
{
case Component::Elevated:
return Theme::Sys::Color::Surface_Tint_Color;
default:
return Theme::Sys::Color::None;
}
}
Theme::Sys::Color ButtonData::getLabelTextColor() const
{
if (auto iter = mLabelTextColors.find(std::make_pair(mComponent, mState)); iter != mLabelTextColors.end())
{
return iter->second;
}
else
{
if (mState == State::Enabled)
{
return getContainerColor();
}
else if (auto iter = mLabelTextColors.find(std::make_pair(mComponent, State::Enabled)); iter != mLabelTextColors.end())
{
return iter->second;
}
else
{
return getContainerColor();
}
}
}
Theme::Sys::Elevation ButtonData::getContainerElevation() const
{
if (auto iter = mContainerElevations.find(std::make_pair(mComponent, mState)); iter != mContainerElevations.end())
{
return iter->second;
}
else
{
if (mState == State::Enabled)
{
return DEFAULT_CONTAINER_ELEVATION;
}
else if (auto iter = mContainerElevations.find(std::make_pair(mComponent, State::Enabled)); iter != mContainerElevations.end())
{
return iter->second;
}
else
{
return DEFAULT_CONTAINER_ELEVATION;
}
}
}
float ButtonData::getStateLayerOverlayOpacity() const
{
if (auto iter = mContainerOpacity.find(std::make_pair(mComponent, mState)); iter != mContainerOpacity.end())
{
return iter->second;
}
else
{
if (mState == State::Enabled)
{
return DEFAULT_CONTAINER_OPACITY;
}
else if (auto iter = mContainerOpacity.find(std::make_pair(mComponent, State::Enabled)); iter != mContainerOpacity.end())
{
return iter->second;
}
else
{
return DEFAULT_CONTAINER_OPACITY;
}
}
}
Theme::Sys::Typescale ButtonData::getLabelTypescale() const
{
switch (mComponent)
{
case Component::Elevated:
return Theme::Sys::Typescale::Label_Large;
default:
return Theme::Sys::Typescale::Label_Large;
}
}
bool ButtonData::canHaveIcon() const
{
switch (mComponent)
{
case Component::Elevated:
return true;
default:
return false;
}
}
Theme::Sys::Color ButtonData::getIconColor() const
{
switch (mComponent)
{
case Component::Elevated:
return Theme::Sys::Color::Primary;
default:
return Theme::Sys::Color::None;
}
}
unsigned ButtonData::getContainerHeight() const
{
switch (mComponent)
{
case Component::Elevated:
case Component::Filled:
return 40;
default:
return 40;
}
}
unsigned ButtonData::getContainerCornerRadius() const
{
switch (mComponent)
{
case Component::Elevated:
case Component::Filled:
return 20;
default:
return 20;
}
}
unsigned ButtonData::getIconSize() const
{
switch (mComponent)
{
case Component::Elevated:
case Component::Filled:
return 18;
default:
return 18;
}
}
unsigned ButtonData::getLeftRightPadding() const
{
switch (mComponent)
{
case Component::Elevated:
case Component::Filled:
return 24;
default:
return 24;
}
}
unsigned ButtonData::getLeftPaddingWithIcon() const
{
switch (mComponent)
{
case Component::Elevated:
case Component::Filled:
return 16;
default:
return 16;
}
}
unsigned ButtonData::getRightPaddingWithIcon() const
{
switch (mComponent)
{
case Component::Elevated:
case Component::Filled:
return 24;
default:
return 24;
}
}
unsigned ButtonData::getBetweenElementPadding() const
{
switch (mComponent)
{
case Component::Elevated:
case Component::Filled:
return 8;
default:
return 8;
}
}
ButtonData::LabelTextAlign ButtonData::getLabelTextAlign() const
{
switch (mComponent)
{
case Component::Elevated:
case Component::Filled:
return ButtonData::LabelTextAlign::Centre;
default:
return ButtonData::LabelTextAlign::Centre;
}
}

View file

@ -0,0 +1,86 @@
#pragma once
#include "ITheme.h"
#include "FontTokens.h"
#include "ElevationTokens.h"
#include <unordered_map>
class ButtonData
{
public:
enum class State
{
Enabled,
Disabled,
Hovered,
Focused,
Pressed
};
enum class Component
{
Elevated,
Filled,
Filled_Tonal,
Outlined,
Text,
Icon,
Segmented,
Floating_Action,
Extended_Floating_Action
};
enum class LabelTextAlign
{
Centre
};
Theme::Sys::Color getContainerColor() const;
Theme::Sys::Color getContainerShadowColor() const;
Theme::Sys::Color getContainerSurfaceTintColor() const;
Theme::Sys::Elevation getContainerElevation() const;
Theme::Sys::Color getLabelTextColor() const;
Theme::Sys::Typescale getLabelTypescale() const;
bool canHaveIcon() const;
Theme::Sys::Color getIconColor() const;
float getStateLayerOverlayOpacity() const;
unsigned getContainerHeight() const;
unsigned getContainerCornerRadius() const;
unsigned getIconSize() const;
unsigned getLeftRightPadding() const;
unsigned getLeftPaddingWithIcon() const;
unsigned getRightPaddingWithIcon() const;
unsigned getBetweenElementPadding() const;
LabelTextAlign getLabelTextAlign() const;
State mState{ State::Enabled };
Component mComponent{ Component::Elevated };
private:
using ComponentState = std::pair<Component, State>;
static const std::unordered_map<ComponentState, Theme::Sys::Color> mContainerColors;
static const std::unordered_map<ComponentState, Theme::Sys::Color> mContainerShadowColors;
static const std::unordered_map<ComponentState, Theme::Sys::Elevation> mContainerElevations;
static const std::unordered_map<ComponentState, float> mContainerOpacity;
static const std::unordered_map<ComponentState, Theme::Sys::Color> mLabelTextColors;
static const std::unordered_map<ComponentState, Theme::Sys::Typescale> mLabelTypescales;
static const std::unordered_map<ComponentState, float> mLabelTextOpacity;
static const std::unordered_map<ComponentState, Theme::Sys::Color> mIconColors;
static const std::unordered_map<ComponentState, float> mIconOpacity;
static const Theme::Sys::Color DEFAULT_CONTAINER_COLOR{ Theme::Sys::Color::None };
static const Theme::Sys::Color DEFAULT_CONTAINER_SHADOW_COLOR{ Theme::Sys::Color::None };
static const Theme::Sys::Elevation DEFAULT_CONTAINER_ELEVATION{ Theme::Sys::Elevation::Level_0 };
static const float DEFAULT_CONTAINER_OPACITY;
};

View file

@ -2,6 +2,7 @@ set(MODULE_NAME ui_controls)
list(APPEND HEADERS
Button.h
ButtonData.h
ButtonGroup.h
Label.h
HorizontalSpacer.h
@ -12,6 +13,7 @@ list(APPEND HEADERS
list(APPEND LIB_INCLUDES
Button.cpp
ButtonData.cpp
ButtonGroup.cpp
Label.cpp
HorizontalSpacer.cpp