Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Color Clipboard #3100

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
11 changes: 5 additions & 6 deletions src/gui/item_action.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,18 @@

#include "gui/item_action.hpp"

ItemAction::ItemAction(const std::string& text, int id, std::function<void()> callback) :
MenuItem(text, id),
ItemAction::ItemAction(const std::string& text, int id, std::function<void()> callback, const Color& text_color) :
MenuItem(text, id, text_color),
m_callback(std::move(callback))
{
}

void
ItemAction::process_action(const MenuAction& action)
{
if (action == MenuAction::HIT) {
if (m_callback) {
m_callback();
}
if (action == MenuAction::HIT && m_callback)
{
m_callback();
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/gui/item_action.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
class ItemAction final : public MenuItem
{
public:
ItemAction(const std::string& text, int id = -1, std::function<void()> callback = {});
ItemAction(const std::string& text, int id = -1, std::function<void()> callback = {}, const Color& text_color = Color(1.f, 1.f, 1.f));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we have a Color::WHITE constant somewhere?


virtual void process_action(const MenuAction& action) override;

Expand Down
12 changes: 12 additions & 0 deletions src/gui/menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,18 @@ Menu::add_entry(const std::string& text, const std::function<void()>& callback)
return add_item<ItemAction>(text, -1, callback);
}

ItemAction&
Menu::add_entry(int id, const std::string& text, const Color& text_color)
{
return add_item<ItemAction>(text, id, [](){}, text_color);
}

ItemAction&
Menu::add_entry(const std::string& text, const std::function<void()>& callback, const Color& text_color)
{
return add_item<ItemAction>(text, -1, callback, text_color);
}

ItemInactive&
Menu::add_inactive(const std::string& text, bool default_color)
{
Expand Down
2 changes: 2 additions & 0 deletions src/gui/menu.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,9 @@ class Menu
ItemHorizontalLine& add_hl();
ItemLabel& add_label(const std::string& text);
ItemAction& add_entry(int id, const std::string& text);
ItemAction& add_entry(int id, const std::string& text, const Color& text_color);
ItemAction& add_entry(const std::string& text, const std::function<void()>& callback);
ItemAction& add_entry(const std::string& text, const std::function<void()>& callback, const Color& text_color);
ItemToggle& add_toggle(int id, const std::string& text, bool* toggled, bool center_text = false);
ItemToggle& add_toggle(int id, const std::string& text,
const std::function<bool()>& get_func,
Expand Down
95 changes: 87 additions & 8 deletions src/gui/menu_color.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// SuperTux
// Copyright (C) 2015 Hume2 <[email protected]>
// 2024 bruhmoent
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
Expand All @@ -14,30 +15,108 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

#include <sstream>

#include "gui/menu_color.hpp"
#include "gui/menu_item.hpp"
#include "util/log.hpp"

#include "util/gettext.hpp"

ColorMenu::ColorMenu(Color* color_) :
color(color_)
ColorMenu::ColorMenu(Color* color) :
m_color(color)
{
add_label(_("Mix the colour"));
add_hl();

add_color_picker_2d(*color);
add_color_channel_rgba(&(color->red), Color::RED);
add_color_channel_rgba(&(color->green), Color::GREEN);
add_color_channel_rgba(&(color->blue), Color::BLUE);
add_color_channel_rgba(&(color->alpha), Color::BLACK, -1, true);
add_color_display(color);
add_color_picker_2d(*m_color);
add_color_channel_rgba(&(m_color->red), Color::RED);
add_color_channel_rgba(&(m_color->green), Color::GREEN);
add_color_channel_rgba(&(m_color->blue), Color::BLUE);
add_color_channel_rgba(&(m_color->alpha), Color::BLACK, -1, true);
add_color_display(m_color);

add_hl();
add_entry(MNID_COPY_CLIPBOARD_RGB, _("Copy to clipboard (rgb)"));
add_entry(MNID_COPY_CLIPBOARD_HEX, _("Copy to clipboard (hex)"));
if (SDL_HasClipboardText())
{
char* clipboard_text = SDL_GetClipboardText();
std::optional<Color> clipboard_color;

if (clipboard_text)
{
const std::string text(clipboard_text);
SDL_free(clipboard_text);

clipboard_color = Color::deserialize_from_rgb(text);
if (!clipboard_color)
clipboard_color = Color::deserialize_from_hex(text);
}

add_entry(MNID_PASTE_CLIPBOARD, _("Paste from clipboard"), clipboard_color.value_or(Color(1.f, 1.f, 1.f)));
}
else
add_entry(MNID_PASTE_CLIPBOARD, _("Paste from clipboard"), Color(1.f, 1.f, 1.f));
tobbi marked this conversation as resolved.
Show resolved Hide resolved

add_hl();
add_back(_("OK"));
}

void
ColorMenu::copy_to_clipboard(const std::string& color_str)
{
if (SDL_SetClipboardText(color_str.c_str()) != 0)
log_warning << "Failed to set SDL clipboard text: " << SDL_GetError() << std::endl;

MenuItem& menu_paste_item = get_item_by_id(MNID_PASTE_CLIPBOARD);
menu_paste_item.set_text_color(*m_color);
}

void
ColorMenu::menu_action(MenuItem& item)
{
if (item.get_id() == MNID_COPY_CLIPBOARD_RGB)
{
if (m_color)
{
const std::string clipboard_text(Color::serialize_to_rgb(*m_color));
copy_to_clipboard(clipboard_text);
}
}
else if (item.get_id() == MNID_COPY_CLIPBOARD_HEX)
{
if (m_color)
{
const std::string clipboard_text(Color::serialize_to_hex(*m_color));
copy_to_clipboard(clipboard_text);
}
}
else if (item.get_id() == MNID_PASTE_CLIPBOARD)
{
if (SDL_HasClipboardText())
{
char* clipboard_text = SDL_GetClipboardText();
if (!clipboard_text)
return;

const std::string text(clipboard_text);
SDL_free(clipboard_text);

std::optional<Color> clipboard_color = Color::deserialize_from_rgb(text);
if (!clipboard_color)
clipboard_color = Color::deserialize_from_hex(text);

if (clipboard_color)
{
*m_color = *clipboard_color;
MenuItem& menu_paste_item = get_item_by_id(MNID_PASTE_CLIPBOARD);
menu_paste_item.set_text_color(*clipboard_color);
}
else
log_warning << "Invalid color format: " << text << ". Supported formats: rgb(r,g,b) and #rrggbb" << std::endl;
}
}
}

/* EOF */
15 changes: 13 additions & 2 deletions src/gui/menu_color.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,23 @@
class ColorMenu final : public Menu
{
public:
ColorMenu(Color* color_);
ColorMenu(Color* color);

void menu_action(MenuItem& item) override;

private:
Color* color;
void copy_to_clipboard(const std::string& color_str);

private:
enum MenuIDs
{
MNID_COPY_CLIPBOARD_RGB = 1,
MNID_COPY_CLIPBOARD_HEX,
MNID_PASTE_CLIPBOARD
};

private:
Color* m_color;

private:
ColorMenu(const ColorMenu&) = delete;
Expand Down
25 changes: 16 additions & 9 deletions src/gui/menu_item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,17 @@
#include "supertux/resources.hpp"
#include "video/drawing_context.hpp"

//static const float FLICK_CURSOR_TIME = 0.5f;

MenuItem::MenuItem(const std::string& text, int id) :
MenuItem::MenuItem(const std::string& text, int id, const std::optional<Color>& text_color) :
m_id(id),
m_text(text),
m_help(),
m_font(Resources::normal_font)
m_font(Resources::normal_font),
m_text_color(text_color)
{
}

MenuItem::~MenuItem() {

MenuItem::~MenuItem()
{
}

void
Expand All @@ -59,12 +58,20 @@ MenuItem::draw(DrawingContext& context, const Vector& pos, int menu_width, bool
}

Color
MenuItem::get_color() const {
return ColorScheme::Menu::default_color;
MenuItem::get_color() const
{
return m_text_color.value_or(ColorScheme::Menu::default_color);
}

void
MenuItem::set_text_color(const Color& color)
{
m_text_color = color;
}

int
MenuItem::get_width() const {
MenuItem::get_width() const
{
return static_cast<int>(m_font->get_text_width(m_text)) + 16;
}

Expand Down
5 changes: 4 additions & 1 deletion src/gui/menu_item.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@
#define HEADER_SUPERTUX_GUI_MENU_ITEM_HPP

#include "gui/menu.hpp"
#include <optional>

class MenuItem
{
public:
MenuItem(const std::string& text, int id = -1);
explicit MenuItem(const std::string& text, int id = -1, const std::optional<Color>& text_color = std::nullopt);
virtual ~MenuItem();

int get_id() const { return m_id; }
Expand Down Expand Up @@ -65,6 +66,7 @@ class MenuItem
virtual void event(const SDL_Event& ev) { }

virtual Color get_color() const;
virtual void set_text_color(const Color& color);

/** Returns true when the MenuManager shouldn't do anything else. */
virtual bool no_other_action() const {
Expand All @@ -86,6 +88,7 @@ class MenuItem
std::string m_text;
std::string m_help;
FontPtr m_font;
std::optional<Color> m_text_color;
bruhmoent marked this conversation as resolved.
Show resolved Hide resolved

private:
MenuItem(const MenuItem&) = delete;
Expand Down
73 changes: 73 additions & 0 deletions src/video/color.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

#include "math/util.hpp"
#include "video/color.hpp"

#include <assert.h>
#include <iomanip>
#include <regex>
#include <sstream>

const Color Color::BLACK(0.0, 0.0, 0.0);
const Color Color::RED(1.0, 0.0, 0.0);
Expand Down Expand Up @@ -116,4 +120,73 @@ Color::toVector()
return result;
}

std::optional<Color>
Color::deserialize_from_rgb(const std::string & rgb_string)
{
const std::regex rgb_format(R"(^\s*rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*$)");
std::smatch matches;

if (std::regex_match(rgb_string, matches, rgb_format))
{
const int r = std::stoi(matches[1].str());
const int g = std::stoi(matches[2].str());
const int b = std::stoi(matches[3].str());

if (math::in_bounds(r, 0, 255) && math::in_bounds(g, 0, 255) && math::in_bounds(b, 0, 255))
{
return Color(static_cast<float>(r) / 255.0f,
static_cast<float>(g) / 255.0f,
static_cast<float>(b) / 255.0f,
1.0f);
}
}
return std::nullopt;
}

std::optional<Color>
Color::deserialize_from_hex(const std::string& hex_string)
{
const std::regex hex_format(R"(^\s*#([A-Fa-f0-9]{6})\s*$)");
std::smatch matches;

if (std::regex_match(hex_string, matches, hex_format))
{
const std::string hex_value = matches[1].str();
unsigned int hex_color;
std::stringstream ss;
ss << std::hex << hex_value;
ss >> hex_color;

const float r = ((hex_color >> 16) & 0xFF) / 255.0f;
const float g = ((hex_color >> 8) & 0xFF) / 255.0f;
const float b = (hex_color & 0xFF) / 255.0f;

return Color(r, g, b, 1.0f);
}
return std::nullopt;
}

std::string
Color::serialize_to_hex(const Color& color)
{
std::stringstream ss;
ss << "#"
<< std::hex << std::setfill('0') << std::uppercase
<< std::setw(2) << static_cast<int>(color.red * 255.f)
<< std::setw(2) << static_cast<int>(color.green * 255.f)
<< std::setw(2) << static_cast<int>(color.blue * 255.f);
return ss.str();
}

std::string
Color::serialize_to_rgb(const Color& color)
{
std::stringstream ss;
ss << "rgb("
<< static_cast<int>(color.red * 255.f) << ","
<< static_cast<int>(color.green * 255.f) << ","
<< static_cast<int>(color.blue * 255.f) << ")";
return ss.str();
}

/* EOF */
Loading
Loading