From a4460f6d9453bbd7e584937686449cef3e19f052 Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Mon, 20 Aug 2018 20:34:57 -0400 Subject: Initial commit --- src/gui/button.cpp | 191 +++++++++++++++++++++++++ src/gui/button.hpp | 83 +++++++++++ src/gui/colors.cpp | 101 +++++++++++++ src/gui/colors.hpp | 55 ++++++++ src/gui/gui.hpp | 28 ++++ src/gui/menu.cpp | 74 ++++++++++ src/gui/menu.hpp | 53 +++++++ src/gui/position.cpp | 107 ++++++++++++++ src/gui/position.hpp | 73 ++++++++++ src/gui/window.hpp | 181 ++++++++++++++++++++++++ src/gui/window_events.cpp | 112 +++++++++++++++ src/gui/window_events_keyboard.cpp | 107 ++++++++++++++ src/gui/window_events_keyboard.hpp | 32 +++++ src/gui/window_events_mouse.cpp | 166 ++++++++++++++++++++++ src/gui/window_events_mouse.hpp | 37 +++++ src/gui/window_main.cpp | 102 ++++++++++++++ src/gui/window_rendering.cpp | 282 +++++++++++++++++++++++++++++++++++++ 17 files changed, 1784 insertions(+) create mode 100644 src/gui/button.cpp create mode 100644 src/gui/button.hpp create mode 100644 src/gui/colors.cpp create mode 100644 src/gui/colors.hpp create mode 100644 src/gui/gui.hpp create mode 100644 src/gui/menu.cpp create mode 100644 src/gui/menu.hpp create mode 100644 src/gui/position.cpp create mode 100644 src/gui/position.hpp create mode 100644 src/gui/window.hpp create mode 100644 src/gui/window_events.cpp create mode 100644 src/gui/window_events_keyboard.cpp create mode 100644 src/gui/window_events_keyboard.hpp create mode 100644 src/gui/window_events_mouse.cpp create mode 100644 src/gui/window_events_mouse.hpp create mode 100644 src/gui/window_main.cpp create mode 100644 src/gui/window_rendering.cpp (limited to 'src/gui') diff --git a/src/gui/button.cpp b/src/gui/button.cpp new file mode 100644 index 0000000..daa224f --- /dev/null +++ b/src/gui/button.cpp @@ -0,0 +1,191 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2018 Leo Tenenbaum +// This file is part of GraphColoring. +// +// GraphColoring is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// GraphColoring is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with GraphColoring. If not, see . +//////////////////////////////////////////////////////////////////////////////// + +#include "button.hpp" + +#include + +#include "utils/geometry.hpp" + +namespace gui { + +const std::vector Button::MOUSE_BUTTONS = { + GDK_BUTTON_PRIMARY, GDK_BUTTON_MIDDLE, GDK_BUTTON_SECONDARY}; + +Button::Button(Window* window_, const std::string& text_, + Position position_, Size size_, Color color_, + Position::Alignment horizontal_align_, Position::Alignment vertical_align_, + Shape shape_) + : window(window_), + text(text_), + position(position_), + size(size_), + color(color_), + horizontal_align(horizontal_align_), + vertical_align(vertical_align_), + shape(shape_), + hovering(false) +{ + // Given a mouse button, this lambda gives the appropriate + // mouse_callback_t (which will call CheckClick with the button). + std::function callback = + [this](guint button)->Window::mouse_callback_t { + return [this,button](Window*,int,int) { + CheckClick(button); + }; + }; + + + + for (guint button : MOUSE_BUTTONS) + { + // Initialize callbacks. + callbacks[button] = std::vector(); + int callback_id = window->SetMouseupCallback(callback(button), button); + mouseup_callback_ids.push_back(callback_id); + } +} + +Button::~Button() +{ + int i; + for (i = 0; i < (int)MOUSE_BUTTONS.size(); i++) + window->RemoveMouseupCallback(mouseup_callback_ids[i],MOUSE_BUTTONS[i]); +} + + + +void Button::CheckHovering() +{ + int mx = window->GetMouseX(), my = window->GetMouseY(); + hovering = shape == Shape::RECTANGLE + ? utils::geometry::InRectangle(mx, my, GetX(), GetY(), + GetWidth(), GetHeight()) + : utils::geometry::InCircle(mx, my, + GetX()+GetRadius(), GetY()+GetRadius(), GetRadius()); + if (hovering) + for (callback_t callback : hover_callbacks) + callback(); +} + +void Button::CheckClick(guint button) +{ + CheckHovering(); + if (hovering) + { + for (callback_t callback : callbacks[button]) + { + callback(); + } + } +} + +void Button::Render() +{ + CheckHovering(); + window->SetLineWidth(BORDER_WIDTH); + window->SetDrawColor(colors::Shade(color, 0.3)); + if (shape == Shape::CIRCLE) + window->SetTextSize(GetRadius()*CIRCLE_TEXT_SIZE_FACTOR); + else + window->SetTextSize(GetHeight()*TEXT_SIZE_FACTOR); + + if (hovering) + { + switch (shape) + { + case Shape::RECTANGLE: + window->DrawRectangle(GetX()+BORDER_WIDTH/2, GetY()+BORDER_WIDTH/2, + GetWidth()-BORDER_WIDTH, GetHeight()-BORDER_WIDTH, true); + break; + case Shape::CIRCLE: + window->DrawCircle(GetX()+GetRadius(), GetY()+GetRadius(), + GetRadius()-BORDER_WIDTH); + break; + } + } + + window->SetDrawColor(color); + switch (shape) + { + case Shape::RECTANGLE: + window->DrawRectangle(GetX(), GetY(), GetWidth(), GetHeight(), false); + break; + case Shape::CIRCLE: + window->DrawCircle(GetX()+GetRadius(), GetY()+GetRadius(), GetRadius(), + false); + break; + } + + int text_x = 0, text_y = 0; + switch (shape) + { + case Shape::RECTANGLE: + { + Position text_pos(GetX(), GetY(), 0.5, 0.5, &size); + text_x = text_pos.X(); + text_y = text_pos.Y(); + } + break; + case Shape::CIRCLE: + text_x = GetX() + GetRadius(); + text_y = GetY() + GetRadius(); + break; + } + + Position text_pos(text_x, text_y); + window->DrawText(text, text_pos, Alignment::CENTER, Alignment::CENTER); +} + +void Button::SetCommand(callback_t callback, guint button) +{ + callbacks[button].push_back(callback); +} + +void Button::SetHoverCallback(callback_t callback) +{ + hover_callbacks.push_back(callback); +} + +int Button::GetWidth() const { return size.X(); } +int Button::GetHeight() const { return size.Y(); } +int Button::GetRadius() const { return size.X(); } + +int Button::GetX() const +{ + return position.AlignedX(horizontal_align, GetWidth()); +} + +int Button::GetY() const +{ + return position.AlignedY(vertical_align, GetHeight()); +} + +void Button::SetPosition(Position position_) +{ + position = position_; +} + +void Button::SetAlignment(Alignment horizontal_align_,Alignment vertical_align_) +{ + horizontal_align = horizontal_align_; + vertical_align = vertical_align_; +} + + +} // namespace gui diff --git a/src/gui/button.hpp b/src/gui/button.hpp new file mode 100644 index 0000000..29a071f --- /dev/null +++ b/src/gui/button.hpp @@ -0,0 +1,83 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2018 Leo Tenenbaum +// This file is part of GraphColoring. +// +// GraphColoring is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// GraphColoring is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with GraphColoring. If not, see . +//////////////////////////////////////////////////////////////////////////////// + +#ifndef GRAPHCOLORING_GUI_BUTTON_H_ +#define GRAPHCOLORING_GUI_BUTTON_H_ + + +#include +#include +#include +#include + +#include "colors.hpp" +#include "position.hpp" +#include "window.hpp" + +namespace gui { + +class Button +{ +public: + typedef std::function callback_t; + typedef std::map> callback_map_t; + enum class Shape + { + RECTANGLE, + CIRCLE // NOTE: If you select this, size.X() will be used for the radius of the circle. + }; + Button(Window* window, const std::string& text, Position pos, Size size, + Color color, + Position::Alignment horizontal_align = Position::Alignment::LEFT, + Position::Alignment vertical_align = Position::Alignment::TOP, + Shape shape = Shape::RECTANGLE); + virtual ~Button(); + void SetCommand(callback_t callback, guint button = GDK_BUTTON_PRIMARY); + void SetHoverCallback(callback_t callback); + void Render(); + int GetX() const; + int GetY() const; + int GetWidth() const; + int GetHeight() const; + int GetRadius() const; + void SetPosition(Position position); + void SetAlignment(Alignment horizontal_align, Alignment vertical_align); + static constexpr double CIRCLE_TEXT_SIZE_FACTOR = 0.9; // Allows for ~2 characters +private: + void CheckHovering(); + void CheckClick(guint button); + static constexpr int BORDER_WIDTH = 3; + static constexpr double TEXT_SIZE_FACTOR = 0.7; + static const std::vector MOUSE_BUTTONS; + Window* const window; + std::string text; + Position position; + Size size; + Color color; + Alignment horizontal_align, vertical_align; + Shape shape; + bool hovering; + std::vector mouseup_callback_ids; + callback_map_t callbacks; + std::vector hover_callbacks; +}; + +} // namespace gui + + +#endif // GRAPHCOLORING_GUI_BUTTON_H_ diff --git a/src/gui/colors.cpp b/src/gui/colors.cpp new file mode 100644 index 0000000..9ab75a8 --- /dev/null +++ b/src/gui/colors.cpp @@ -0,0 +1,101 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2018 Leo Tenenbaum +// This file is part of GraphColoring. +// +// GraphColoring is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// GraphColoring is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with GraphColoring. If not, see . +//////////////////////////////////////////////////////////////////////////////// + +#include "colors.hpp" +#include "utils/errors.hpp" + +#include + + +#define SHADE_FACTOR 1.5 + +namespace gui { +namespace colors { + +void Unpack(Color color, uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) +{ + *r = (color >> 24) & 0xFF; + *g = (color >> 16) & 0xFF; + *b = (color >> 8) & 0xFF; + *a = (color >> 0) & 0xFF; +} + +Color Pack(uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + return (r << 24) + (g << 16) + (b << 8) + (a << 0); +} + +static uint8_t shade_channel(uint8_t channel, double factor) +{ + if (channel * factor > 0xFF) + channel = 0xFF; + else + channel *= factor; + return channel; +} + +Color Shade(Color color, double factor) +{ + uint8_t r, g, b, a; + Unpack(color, &r, &g, &b, &a); + r = shade_channel(r, factor); + g = shade_channel(g, factor); + b = shade_channel(b, factor); + a = shade_channel(a, factor); + return Pack(r, g, b, a); +} + +Color Light(Color color) +{ + return Shade(color, SHADE_FACTOR); +} + +Color Dark(Color color) +{ + return Shade(color, 1/SHADE_FACTOR); +} + +Color FromString(const std::string& str) +{ + uint8_t r, g, b, a; + try + { + r = std::stoi(str.substr(1,2),nullptr,16); + g = std::stoi(str.substr(3,2),nullptr,16); + b = std::stoi(str.substr(5,2),nullptr,16); + if (str.length() >= 9) + a = std::stoi(str.substr(7,2),nullptr,16); + else + a = 255; + + return Pack(r, g, b, a); + } + catch (std::invalid_argument&) + { + utils::errors::Die("Invalid color string: " + str); + } + return 0; +} + +Color FromAttribute(pugi::xml_attribute attr) +{ + return FromString(std::string(attr.value())); +} + +} // namespace colors +} // namespace gui diff --git a/src/gui/colors.hpp b/src/gui/colors.hpp new file mode 100644 index 0000000..0ecefb0 --- /dev/null +++ b/src/gui/colors.hpp @@ -0,0 +1,55 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2018 Leo Tenenbaum +// This file is part of GraphColoring. +// +// GraphColoring is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// GraphColoring is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with GraphColoring. If not, see . +//////////////////////////////////////////////////////////////////////////////// + +#ifndef GRAPHCOLORING_GUI_COLORS_H_ +#define GRAPHCOLORING_GUI_COLORS_H_ + +#include +#include + +#include "pugi/pugixml.hpp" + +namespace gui { + +typedef uint32_t Color; + +namespace colors { + +// Color constants +static constexpr Color WHITE = 0xFFFFFFFF; +static constexpr Color BLACK = 0x000000FF; +static constexpr Color RED = 0xFF0000FF; +static constexpr Color GREEN = 0x00FF00FF; +static constexpr Color BLUE = 0x0000FFFF; +static constexpr Color YELLOW = 0xFFFF00FF; +static constexpr Color CYAN = 0x00FFFFFF; +static constexpr Color MAGENTA = 0xFF00FFFF; + +extern void Unpack(Color color, + uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a); // 32-bit color => 8-bit channels +extern Color Pack(uint8_t r, uint8_t g, uint8_t b, uint8_t a); // 8-bit channels => 32-bit color +extern Color Shade(Color color, double factor); +extern Color Light(Color color); +extern Color Dark(Color color); +extern Color FromString(const std::string& str); // Reads #FF00AA or #AA33FFCC +extern Color FromAttribute(pugi::xml_attribute attr); + +} // namespace colors +} // namespace gui + +#endif // GRAPHCOLORING_GUI_COLORS_H_ diff --git a/src/gui/gui.hpp b/src/gui/gui.hpp new file mode 100644 index 0000000..a9aea3e --- /dev/null +++ b/src/gui/gui.hpp @@ -0,0 +1,28 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2018 Leo Tenenbaum +// This file is part of GraphColoring. +// +// GraphColoring is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// GraphColoring is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with GraphColoring. If not, see . +//////////////////////////////////////////////////////////////////////////////// + +#ifndef GRAPHCOLORING_GUI_GUI_H_ +#define GRAPHCOLORING_GUI_GUI_H_ + +#include "button.hpp" +#include "colors.hpp" +#include "menu.hpp" +#include "position.hpp" +#include "window.hpp" + +#endif // GRAPHCOLORING_GUI_GUI_H_ diff --git a/src/gui/menu.cpp b/src/gui/menu.cpp new file mode 100644 index 0000000..18bacb2 --- /dev/null +++ b/src/gui/menu.cpp @@ -0,0 +1,74 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2018 Leo Tenenbaum +// This file is part of GraphColoring. +// +// GraphColoring is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// GraphColoring is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with GraphColoring. If not, see . +//////////////////////////////////////////////////////////////////////////////// + +#include "menu.hpp" + +#include + +namespace gui { + +Menu::Menu(Window* window, + const std::vector>& buttons_, + Position position_, Size size_) + : window(window), buttons(buttons_), position(position_), size(size_) +{ + int total_button_height = 0; + for (std::shared_ptr