Created Container and Window.
This commit is contained in:
commit
afd7dc29ad
|
@ -0,0 +1,3 @@
|
|||
/build
|
||||
|
||||
/.vscode
|
|
@ -0,0 +1,24 @@
|
|||
cmake_minimum_required(VERSION 3.16)
|
||||
project(SFTK LANGUAGES CXX)
|
||||
|
||||
set(CXX_STANDARD_REQUIRED 23)
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(SFML
|
||||
GIT_REPOSITORY https://github.com/SFML/SFML.git
|
||||
GIT_TAG 2.6.x)
|
||||
FetchContent_MakeAvailable(SFML)
|
||||
|
||||
set(ROOT src/)
|
||||
set(CONTAINER src/containers)
|
||||
|
||||
set(SOURCES ${SOURCES} ${ROOT}/window.cpp)
|
||||
set(SOURCES ${SOURCES} ${CONTAINER}/container.cpp)
|
||||
|
||||
add_library(sftk SHARED ${SOURCES})
|
||||
target_link_libraries(sftk PRIVATE sfml-graphics sfml-audio sfml-network)
|
||||
target_include_directories(sftk PUBLIC include/)
|
||||
|
||||
add_executable(demo1 demo/demo1.cpp)
|
||||
target_link_libraries(demo1 PRIVATE sftk sfml-graphics sfml-audio sfml-network)
|
||||
target_include_directories(demo1 PRIVATE include/)
|
|
@ -0,0 +1,9 @@
|
|||
#include <sftk.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
auto &window = sftk::Window::create(800, 600, L"demo1");
|
||||
auto container = sftk::Container::create(vec(100.f, 100.f), vec(400.f, 400.f), window.getRoot());
|
||||
container->setBackgroudColor(sf::Color::White);
|
||||
window.exec();
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
#ifndef CONTAINER_HPP
|
||||
#define CONTAINER_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
#include <exceptions.hpp>
|
||||
#include <event.hpp>
|
||||
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
namespace sftk
|
||||
{
|
||||
class Container;
|
||||
|
||||
typedef std::shared_ptr<Container> pContainer;
|
||||
bool operator==(pContainer &shp, Container *rawp);
|
||||
|
||||
class Container
|
||||
{
|
||||
public: // Public base functions
|
||||
static pContainer create(pContainer parent = nullptr);
|
||||
static pContainer create(sf::Vector2f pos, sf::Vector2f size, pContainer parent = nullptr);
|
||||
|
||||
void setParent(pContainer parent);
|
||||
void setPosition(sf::Vector2f pos = sf::Vector2f(0, 0));
|
||||
void setSize(sf::Vector2f pos);
|
||||
void setBackgroudColor(sf::Color color);
|
||||
|
||||
pContainer getParent() const;
|
||||
const sf::Vector2f &getPosition() const;
|
||||
const sf::Vector2f &getSize() const;
|
||||
sf::FloatRect getGlobalBouds() const;
|
||||
|
||||
virtual bool isRoot() const;
|
||||
virtual bool hasInternalChange() const;
|
||||
|
||||
virtual void update() const;
|
||||
|
||||
public: // Event hadler register functions
|
||||
template <class T>
|
||||
void registerEvent(EventType type, std::function<T> handler);
|
||||
|
||||
public: // Static and operators
|
||||
static pContainer getRoot(Container *p = nullptr);
|
||||
|
||||
friend bool sftk::operator==(pContainer &shp, Container *rawp);
|
||||
|
||||
protected: // Must be overrided by child classes
|
||||
Container(pContainer parent = nullptr);
|
||||
Container(sf::Vector2f pos, sf::Vector2f size, pContainer parent = nullptr);
|
||||
Container(sf::Vector2f pos, sf::Vector2f size, bool root);
|
||||
|
||||
virtual sf::RenderWindow &windowSFWindow();
|
||||
|
||||
// The events bases on sfml's Event,
|
||||
// so the Window class must use this function to
|
||||
// pass event to the root container
|
||||
// (itself's parent class)'s dispatchEvent(Event&)
|
||||
// to process it as Event.
|
||||
void dispatchEvent(sf::Event &event);
|
||||
|
||||
private: // For this class to use
|
||||
sf::RenderWindow &getSfWindow();
|
||||
// When this container did deal with the passed event
|
||||
// it returns true. On the oppsite case it returns false.
|
||||
bool dispatchEvent(Event &event);
|
||||
|
||||
pContainer parent;
|
||||
std::vector<pContainer> childs;
|
||||
sf::Vector2f basepos;
|
||||
sf::Vector2f pos, size;
|
||||
|
||||
sf::View view;
|
||||
|
||||
sf::Color backgroudColor;
|
||||
|
||||
static const int64_t maxClickTime = 300;
|
||||
|
||||
private: // Called on construction
|
||||
static void rootTest(Container *self);
|
||||
inline static int64_t currentTime();
|
||||
|
||||
private: // Event handlers
|
||||
std::function<void()> closed;
|
||||
std::function<void(sf::Vector2f)> resized;
|
||||
std::function<void(sf::Vector2f, sf::Mouse::Button)> mousePressed;
|
||||
std::function<void(sf::Vector2f, sf::Mouse::Button)> mouseReleased;
|
||||
std::function<void(sf::Vector2f, sf::Mouse::Button)> mouseClicked;
|
||||
std::function<void(sf::Vector2f)> mouseEntered;
|
||||
std::function<void(sf::Vector2f)> mouseLeft;
|
||||
std::function<void(sf::Vector2f)> mouseMoved;
|
||||
std::function<void(sf::Vector2f, sf::Vector2f, sf::Mouse::Button)> mouseDragged;
|
||||
std::function<void(float)> mouseScrolled;
|
||||
std::function<void(wchar_t)> textInputed;
|
||||
|
||||
private: // Second events asistant vars
|
||||
int64_t lastMousePressTime[sf::Mouse::Button::ButtonCount];
|
||||
sf::Vector2f lastMousePressPos[sf::Mouse::Button::ButtonCount];
|
||||
|
||||
bool focused;
|
||||
bool mouseLocated;
|
||||
|
||||
public: // Exceptions
|
||||
class RootContainerNotPresent : public SFTKException<Container>
|
||||
{
|
||||
public:
|
||||
RootContainerNotPresent(Container *container);
|
||||
const char *what() const noexcept override;
|
||||
};
|
||||
|
||||
class NotAWindowObj : public SFTKException<Container>
|
||||
{
|
||||
public:
|
||||
NotAWindowObj(Container *container);
|
||||
const char *what() const noexcept override;
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,81 @@
|
|||
#ifndef EVENT_HPP
|
||||
#define EVENT_HPP
|
||||
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
namespace sftk
|
||||
{
|
||||
enum EventType
|
||||
{
|
||||
Closed,
|
||||
Resized,
|
||||
MousePressed,
|
||||
MouseReleased,
|
||||
MouseClicked,
|
||||
MouseEntered,
|
||||
MouseLeft,
|
||||
MouseMoved,
|
||||
MouseDragged,
|
||||
MouseScrolled,
|
||||
TextInputed,
|
||||
|
||||
EventTypeLength,
|
||||
};
|
||||
|
||||
struct _Resized
|
||||
{
|
||||
sf::Vector2f size; // The parent Container's new size.
|
||||
};
|
||||
|
||||
struct _MouseEnteredLeftMoved
|
||||
{
|
||||
sf::Vector2f pos;
|
||||
};
|
||||
|
||||
typedef _MouseEnteredLeftMoved MousePosition;
|
||||
|
||||
struct _MousePressedReleasedClicked
|
||||
{
|
||||
sf::Vector2f pos;
|
||||
sf::Mouse::Button button;
|
||||
};
|
||||
|
||||
struct _MouseDragged
|
||||
{
|
||||
sf::Vector2f start;
|
||||
sf::Vector2f now;
|
||||
sf::Mouse::Button button;
|
||||
};
|
||||
|
||||
struct _MouseScrolled
|
||||
{
|
||||
float delta;
|
||||
};
|
||||
|
||||
struct _TextInputed
|
||||
{
|
||||
wchar_t uchar;
|
||||
};
|
||||
|
||||
union EventData
|
||||
{
|
||||
_Resized resized;
|
||||
_MousePressedReleasedClicked mousePressed;
|
||||
_MousePressedReleasedClicked mouseReleased;
|
||||
_MousePressedReleasedClicked mouseClicked;
|
||||
_MouseEnteredLeftMoved mouseEntered;
|
||||
_MouseEnteredLeftMoved mouseLeft;
|
||||
_MouseEnteredLeftMoved mouseMoved;
|
||||
_MouseDragged mouseDragged;
|
||||
_MouseScrolled mouseScrolled;
|
||||
_TextInputed textInputed;
|
||||
};
|
||||
|
||||
struct Event
|
||||
{
|
||||
EventType type;
|
||||
EventData data;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,63 @@
|
|||
#ifndef EXCEPTIONS_HPP
|
||||
#define EXCEPTIONS_HPP
|
||||
|
||||
#include <exception>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
namespace sftk
|
||||
{
|
||||
/**
|
||||
* @brief # SFTK exceptions super class
|
||||
*
|
||||
* @tparam T - The SFTK object types
|
||||
*/
|
||||
template <class T>
|
||||
class SFTKException : public std::exception
|
||||
{
|
||||
public:
|
||||
SFTKException(T *obj) : sftkObj(obj) {}
|
||||
/**
|
||||
* @brief # Address formatter
|
||||
*
|
||||
* This formatter function use 16 `*`s as address placeholder.
|
||||
*
|
||||
* When throwing an exception, Exceptions can use placeholder with this function
|
||||
* to fill the `what()` message. So the reported exception can tell where the crashed
|
||||
* SFTK object at.
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* ```c
|
||||
* const char *SomeException::what() const noexcept
|
||||
* {
|
||||
* static char msg[] = "sftk::SomeClass 0x********_******** reported an exception.";
|
||||
* SFTKException::formatAddress(msg, sizeof(msg));
|
||||
* return msg;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param msg exception message
|
||||
* @param len message length
|
||||
*/
|
||||
void formatAddress(char *msg, int len) const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::hex << std::setw(16) << std::setfill('0') << reinterpret_cast<uintptr_t>(sftkObj);
|
||||
auto it = ss.str().begin();
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
if (msg[i] == '*')
|
||||
{
|
||||
msg[i] = *it;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
T *sftkObj;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef GTYPES_HPP
|
||||
#define GTYPES_HPP
|
||||
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
template <class T>
|
||||
constexpr sf::Vector2<T> vec(T x, T y)
|
||||
{
|
||||
return sf::Vector2(x, y);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr sf::Vector3<T> vec(T x, T y, T z)
|
||||
{
|
||||
return sf::Vector3(x, y, z);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr sf::Rect<T> vec(T x, T y, T width, T height)
|
||||
{
|
||||
return sf::Rect(x, y, width, height);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef SFTK_HPP
|
||||
#define SFTK_HPP
|
||||
|
||||
#include <gtypes.hpp>
|
||||
|
||||
#include <window.hpp>
|
||||
|
||||
#include <containers/container.hpp>
|
||||
|
||||
#endif
|
|
@ -0,0 +1,59 @@
|
|||
#ifndef WINDOW_HPP
|
||||
#define WINDOW_HPP
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <gtypes.hpp>
|
||||
#include <exceptions.hpp>
|
||||
#include <containers/container.hpp>
|
||||
|
||||
namespace sftk
|
||||
{
|
||||
class Window;
|
||||
|
||||
typedef std::shared_ptr<Window> pWindow;
|
||||
|
||||
/**
|
||||
* @brief Window type
|
||||
*
|
||||
* To create a unique SFML window in the current thread.
|
||||
*/
|
||||
class Window : public Container
|
||||
{
|
||||
public:
|
||||
static Window &create(int width, int height, std::wstring name = L"");
|
||||
|
||||
void exec();
|
||||
|
||||
void setSize(sf::Vector2u size);
|
||||
|
||||
bool isRoot() const;
|
||||
|
||||
sf::Vector2f &getPosition() const;
|
||||
|
||||
protected:
|
||||
Window(int width, int height, std::wstring name = L"");
|
||||
|
||||
private:
|
||||
sf::RenderWindow &windowSFWindow();
|
||||
|
||||
sf::RenderWindow sfwindow;
|
||||
|
||||
std::unique_ptr<bool> running;
|
||||
|
||||
private:
|
||||
std::unique_ptr<std::vector<sf::Vector2f>> v2f_dumpst;
|
||||
|
||||
public:
|
||||
class WindowMultipleConstructed : public SFTKException<Window>
|
||||
{
|
||||
public:
|
||||
WindowMultipleConstructed(Window *);
|
||||
const char *what() const noexcept override;
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
#endif
|
|
@ -0,0 +1,524 @@
|
|||
#include <containers/container.hpp>
|
||||
|
||||
#include <gtypes.hpp>
|
||||
#include <window.hpp>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
using namespace sftk;
|
||||
|
||||
pContainer Container::getRoot(Container *p)
|
||||
{
|
||||
static thread_local pContainer root;
|
||||
if (p)
|
||||
root.reset(p);
|
||||
return root;
|
||||
}
|
||||
|
||||
void Container::rootTest(Container *self)
|
||||
{
|
||||
if (!getRoot().get())
|
||||
throw RootContainerNotPresent(self);
|
||||
}
|
||||
|
||||
Container::Container(pContainer parent) : parent(nullptr)
|
||||
{
|
||||
if (!parent.get())
|
||||
{
|
||||
Container::rootTest(this);
|
||||
this->parent = getRoot();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->parent = parent;
|
||||
}
|
||||
this->parent->childs.push_back(pContainer(this));
|
||||
}
|
||||
|
||||
Container::Container(sf::Vector2f pos, sf::Vector2f size, pContainer parent)
|
||||
: parent(nullptr),
|
||||
pos(pos),
|
||||
size(size),
|
||||
view(vec(0.f, 0.f, size.x, size.y)),
|
||||
basepos(parent->basepos + parent->pos),
|
||||
backgroudColor(sf::Color::Black)
|
||||
{
|
||||
if (!parent.get())
|
||||
{
|
||||
Container::rootTest(this);
|
||||
this->parent = getRoot();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->parent = parent;
|
||||
}
|
||||
this->parent->childs.push_back(pContainer(this));
|
||||
auto rootsize = getRoot()->getSize();
|
||||
view.setViewport(vec(
|
||||
(parent->basepos.x + pos.x) / rootsize.x, (parent->basepos.y + pos.y) / rootsize.y,
|
||||
size.x / rootsize.x, size.y / rootsize.y));
|
||||
}
|
||||
|
||||
Container::Container(sf::Vector2f pos, sf::Vector2f size, bool root)
|
||||
: parent(nullptr),
|
||||
pos(pos),
|
||||
size(size),
|
||||
view(vec(0.f, 0.f, size.x, size.y)),
|
||||
basepos(vec(0.f, 0.f)),
|
||||
backgroudColor(sf::Color::Black)
|
||||
{
|
||||
view.setViewport(vec(0.f, 0.f, 1.f, 1.f));
|
||||
}
|
||||
|
||||
pContainer Container::create(pContainer parent)
|
||||
{
|
||||
return pContainer(new Container(parent));
|
||||
}
|
||||
|
||||
pContainer Container::create(sf::Vector2f pos, sf::Vector2f size, pContainer parent)
|
||||
{
|
||||
return pContainer(new Container(pos, size, parent));
|
||||
}
|
||||
|
||||
void Container::setParent(pContainer parent)
|
||||
{
|
||||
auto it = std::find(this->parent->childs.begin(), this->parent->childs.end(), this);
|
||||
this->parent->childs.erase(it);
|
||||
this->parent = parent;
|
||||
this->parent->childs.push_back(pContainer(this));
|
||||
}
|
||||
|
||||
void Container::setPosition(sf::Vector2f pos)
|
||||
{
|
||||
this->pos = pos;
|
||||
auto rootsize = getRoot()->getSize();
|
||||
view.setViewport(vec(
|
||||
(parent->pos.x + pos.x) / rootsize.x, (parent->pos.y + pos.y) / rootsize.y,
|
||||
size.x / rootsize.x, size.y / rootsize.y));
|
||||
}
|
||||
|
||||
void Container::setSize(sf::Vector2f size)
|
||||
{
|
||||
this->size = size;
|
||||
auto rootsize = getRoot()->getSize();
|
||||
view.setViewport(vec(
|
||||
(basepos.x + pos.x) / rootsize.x, (basepos.y + pos.y) / rootsize.y,
|
||||
size.x / rootsize.x, size.y / rootsize.y));
|
||||
}
|
||||
|
||||
void Container::setBackgroudColor(sf::Color color)
|
||||
{
|
||||
backgroudColor = color;
|
||||
}
|
||||
|
||||
pContainer Container::getParent() const
|
||||
{
|
||||
return parent;
|
||||
}
|
||||
|
||||
const sf::Vector2f &Container::getPosition() const
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
|
||||
const sf::Vector2f &Container::getSize() const
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
sf::FloatRect Container::getGlobalBouds() const
|
||||
{
|
||||
return vec(basepos.x + pos.x, basepos.y + pos.y, size.x, size.y);
|
||||
}
|
||||
|
||||
bool Container::isRoot() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Container::hasInternalChange() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void Container::update() const
|
||||
{
|
||||
auto &window = getRoot()->windowSFWindow();
|
||||
window.setView(view);
|
||||
sf::RectangleShape bg(vec(size.x, size.y));
|
||||
bg.setPosition(vec(0.f, 0.f));
|
||||
bg.setFillColor(backgroudColor);
|
||||
window.draw(bg);
|
||||
for (auto c : childs)
|
||||
{
|
||||
c->update();
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void Container::registerEvent(EventType type, std::function<void()> handler)
|
||||
{
|
||||
if (type != EventType::Closed)
|
||||
return;
|
||||
closed = handler;
|
||||
}
|
||||
|
||||
template <>
|
||||
void Container::registerEvent(EventType type, std::function<void(sf::Vector2f)> handler)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case EventType::Resized:
|
||||
resized = handler;
|
||||
break;
|
||||
case EventType::MouseEntered:
|
||||
mouseEntered = handler;
|
||||
break;
|
||||
case EventType::MouseLeft:
|
||||
mouseLeft = handler;
|
||||
break;
|
||||
case EventType::MouseMoved:
|
||||
mouseMoved = handler;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void Container::registerEvent(EventType type, std::function<void(sf::Vector2f, sf::Mouse::Button)> handler)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case EventType::MousePressed:
|
||||
mousePressed = handler;
|
||||
break;
|
||||
case EventType::MouseReleased:
|
||||
mouseReleased = handler;
|
||||
break;
|
||||
case EventType::MouseClicked:
|
||||
mouseClicked = handler;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void Container::registerEvent(EventType type, std::function<void(sf::Vector2f, sf::Vector2f, sf::Mouse::Button)> handler)
|
||||
{
|
||||
if (type != EventType::MouseDragged)
|
||||
return;
|
||||
mouseDragged = handler;
|
||||
}
|
||||
|
||||
template <>
|
||||
void Container::registerEvent(EventType type, std::function<void(float)> handler)
|
||||
{
|
||||
if (type != EventType::MouseScrolled)
|
||||
return;
|
||||
mouseScrolled = handler;
|
||||
}
|
||||
|
||||
template <>
|
||||
void Container::registerEvent(EventType type, std::function<void(wchar_t)> handler)
|
||||
{
|
||||
if (type != EventType::TextInputed)
|
||||
return;
|
||||
textInputed = handler;
|
||||
}
|
||||
|
||||
void Container::dispatchEvent(sf::Event &event)
|
||||
{
|
||||
Event eve{};
|
||||
switch (event.type)
|
||||
{
|
||||
case sf::Event::Closed:
|
||||
eve = Event{.type = EventType::Closed};
|
||||
break;
|
||||
case sf::Event::Resized:
|
||||
eve = Event{
|
||||
.type = EventType::Resized,
|
||||
.data = EventData{
|
||||
.resized = _Resized{
|
||||
.size = vec((float)event.size.width, (float)event.size.height)}}};
|
||||
break;
|
||||
case sf::Event::MouseEntered:
|
||||
eve = Event{
|
||||
.type = EventType::MouseEntered,
|
||||
.data = EventData{
|
||||
.mouseEntered = _MouseEnteredLeftMoved{
|
||||
.pos = vec((float)event.mouseMove.x, (float)event.mouseMove.y)}}};
|
||||
break;
|
||||
case sf::Event::MouseLeft:
|
||||
eve = Event{
|
||||
.type = EventType::MouseLeft,
|
||||
.data = EventData{
|
||||
.mouseLeft = _MouseEnteredLeftMoved{
|
||||
.pos = vec((float)event.mouseMove.x, (float)event.mouseMove.y)}}};
|
||||
break;
|
||||
case sf::Event::MouseButtonPressed:
|
||||
eve = Event{
|
||||
.type = EventType::MousePressed,
|
||||
.data = EventData{
|
||||
.mousePressed = _MousePressedReleasedClicked{
|
||||
.pos = vec((float)event.mouseButton.x, (float)event.mouseButton.y),
|
||||
.button = event.mouseButton.button}}};
|
||||
break;
|
||||
case sf::Event::MouseButtonReleased:
|
||||
eve = Event{
|
||||
.type = EventType::MouseReleased,
|
||||
.data = EventData{
|
||||
.mouseReleased = _MousePressedReleasedClicked{
|
||||
.pos = vec((float)event.mouseButton.x, (float)event.mouseButton.y),
|
||||
.button = event.mouseButton.button}}};
|
||||
break;
|
||||
case sf::Event::MouseMoved:
|
||||
eve = Event{
|
||||
.type = EventType::MouseMoved,
|
||||
.data = EventData{
|
||||
.mouseMoved = MousePosition{
|
||||
.pos = vec((float)event.mouseMove.x, (float)event.mouseMove.y)}}};
|
||||
break;
|
||||
case sf::Event::MouseWheelScrolled:
|
||||
if (event.mouseWheelScroll.wheel != sf::Mouse::VerticalWheel)
|
||||
return;
|
||||
eve = Event{
|
||||
.type = EventType::MouseScrolled,
|
||||
.data = EventData{
|
||||
.mouseScrolled = _MouseScrolled{
|
||||
.delta = event.mouseWheelScroll.delta,
|
||||
}}};
|
||||
break;
|
||||
case sf::Event::TextEntered:
|
||||
eve = Event{
|
||||
.type = EventType::TextInputed,
|
||||
.data = EventData{
|
||||
.textInputed = _TextInputed{
|
||||
.uchar = static_cast<wchar_t>(event.text.unicode)}}};
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
dispatchEvent(eve);
|
||||
}
|
||||
|
||||
bool Container::dispatchEvent(Event &event)
|
||||
{
|
||||
bool spread = true; // If this event will pass to children containers.
|
||||
bool broadcast = false; // If this event will send to all children containers.
|
||||
bool handler_effective = false; // The return value, if this container processed this event.
|
||||
|
||||
_Resized rsz;
|
||||
_MousePressedReleasedClicked mpr;
|
||||
_MousePressedReleasedClicked mrel;
|
||||
_MousePressedReleasedClicked mcli;
|
||||
_MouseEnteredLeftMoved mmov;
|
||||
_MouseDragged mdra;
|
||||
|
||||
switch (event.type)
|
||||
{
|
||||
case EventType::Closed:
|
||||
broadcast = true;
|
||||
if (closed)
|
||||
{
|
||||
handler_effective = true;
|
||||
closed();
|
||||
}
|
||||
break;
|
||||
case EventType::Resized:
|
||||
rsz = event.data.resized;
|
||||
if (resized)
|
||||
{
|
||||
handler_effective = true;
|
||||
resized(rsz.size);
|
||||
}
|
||||
if (isRoot())
|
||||
{
|
||||
setSize(rsz.size);
|
||||
}
|
||||
else
|
||||
{
|
||||
setPosition(pos);
|
||||
setSize(size);
|
||||
}
|
||||
break;
|
||||
case EventType::MousePressed:
|
||||
mpr = event.data.mousePressed;
|
||||
if (mousePressed && getGlobalBouds().contains(mpr.pos))
|
||||
{
|
||||
handler_effective = true;
|
||||
mousePressed(mpr.pos - basepos - pos, mpr.button);
|
||||
}
|
||||
lastMousePressTime[mpr.button] = currentTime();
|
||||
break;
|
||||
case EventType::MouseReleased:
|
||||
mrel = event.data.mouseReleased;
|
||||
lastMousePressTime[mrel.button] = -1;
|
||||
lastMousePressPos[mrel.button] = vec(-1.f, -1.f);
|
||||
if (mouseReleased && getGlobalBouds().contains(mrel.pos))
|
||||
{
|
||||
handler_effective = true;
|
||||
mouseReleased(mrel.pos - basepos - pos, mrel.button);
|
||||
}
|
||||
if (isRoot() &&
|
||||
lastMousePressTime[mrel.button] >= 0 &&
|
||||
lastMousePressTime[mrel.button] < maxClickTime)
|
||||
{
|
||||
auto tmp = Event{
|
||||
.type = EventType::MouseClicked,
|
||||
.data = EventData{
|
||||
.mouseClicked = mrel}};
|
||||
dispatchEvent(tmp);
|
||||
}
|
||||
break;
|
||||
case EventType::MouseClicked:
|
||||
mcli = event.data.mouseClicked;
|
||||
if (mouseClicked && mouseLocated)
|
||||
{
|
||||
handler_effective = true;
|
||||
mouseClicked(mcli.pos - basepos - pos, mcli.button);
|
||||
}
|
||||
if (mouseLocated)
|
||||
{
|
||||
focused = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
focused = false;
|
||||
}
|
||||
break;
|
||||
case EventType::MouseEntered:
|
||||
mouseLocated = true;
|
||||
if (mouseEntered)
|
||||
{
|
||||
handler_effective = true;
|
||||
mouseEntered(event.data.mouseEntered.pos - basepos - pos);
|
||||
}
|
||||
break;
|
||||
case EventType::MouseLeft:
|
||||
mouseLocated = false;
|
||||
if (mouseLeft)
|
||||
{
|
||||
handler_effective = true;
|
||||
mouseLeft(event.data.mouseLeft.pos - basepos - pos);
|
||||
}
|
||||
break;
|
||||
case EventType::MouseMoved:
|
||||
mmov = event.data.mouseMoved;
|
||||
if (getGlobalBouds().contains(mmov.pos))
|
||||
{
|
||||
if (mouseMoved)
|
||||
{
|
||||
handler_effective = true;
|
||||
mouseMoved(mmov.pos - basepos - pos);
|
||||
}
|
||||
if (isRoot() && !mouseLocated)
|
||||
{
|
||||
auto tmp = Event{
|
||||
.type = EventType::MouseEntered,
|
||||
.data = event.data};
|
||||
dispatchEvent(tmp);
|
||||
}
|
||||
}
|
||||
else if (isRoot() && mouseLocated)
|
||||
{
|
||||
auto tmp = Event{
|
||||
.type = EventType::MouseLeft,
|
||||
.data = event.data};
|
||||
dispatchEvent(tmp);
|
||||
}
|
||||
if (!isRoot())
|
||||
break;
|
||||
for (auto i = 0; i < sf::Mouse::Button::ButtonCount; i++)
|
||||
{
|
||||
if (lastMousePressPos[i] == vec(-1.f, -1.f))
|
||||
continue;
|
||||
auto tmp = Event{
|
||||
.type = EventType::MouseDragged,
|
||||
.data = {
|
||||
.mouseDragged = _MouseDragged{
|
||||
.start = lastMousePressPos[i],
|
||||
.now = mmov.pos,
|
||||
.button = (sf::Mouse::Button)i}}};
|
||||
dispatchEvent(tmp);
|
||||
}
|
||||
break;
|
||||
case EventType::MouseDragged:
|
||||
mdra = event.data.mouseDragged;
|
||||
if (mouseDragged)
|
||||
{
|
||||
handler_effective = true;
|
||||
mouseDragged(mdra.start, mdra.now, mdra.button);
|
||||
}
|
||||
break;
|
||||
case EventType::MouseScrolled:
|
||||
if (mouseScrolled)
|
||||
{
|
||||
handler_effective = true;
|
||||
mouseScrolled(event.data.mouseScrolled.delta);
|
||||
}
|
||||
break;
|
||||
case EventType::TextInputed:
|
||||
if (textInputed)
|
||||
{
|
||||
handler_effective = true;
|
||||
textInputed(event.data.textInputed.uchar);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!spread)
|
||||
return handler_effective;
|
||||
|
||||
bool child_handled;
|
||||
bool handler_handled = false;
|
||||
for (auto container : childs)
|
||||
{
|
||||
if ((child_handled = container->dispatchEvent(event)) && !broadcast)
|
||||
{
|
||||
if (child_handled)
|
||||
handler_handled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return handler_handled;
|
||||
}
|
||||
|
||||
sf::RenderWindow &Container::windowSFWindow()
|
||||
{
|
||||
throw NotAWindowObj(const_cast<Container *>(this));
|
||||
}
|
||||
|
||||
sf::RenderWindow &Container::getSfWindow()
|
||||
{
|
||||
return getRoot()->windowSFWindow();
|
||||
}
|
||||
|
||||
bool sftk::operator==(pContainer &shp, Container *rawp)
|
||||
{
|
||||
return shp.get() == rawp;
|
||||
}
|
||||
|
||||
int64_t Container::currentTime()
|
||||
{
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count();
|
||||
}
|
||||
|
||||
Container::RootContainerNotPresent::RootContainerNotPresent(Container *container)
|
||||
: SFTKException(container) {}
|
||||
|
||||
const char *Container::RootContainerNotPresent::what() const noexcept
|
||||
{
|
||||
static char msg[] = "sftk::Container 0x********_********: Root container not present.";
|
||||
SFTKException::formatAddress(msg, sizeof(msg));
|
||||
return msg;
|
||||
}
|
||||
|
||||
Container::NotAWindowObj::NotAWindowObj(Container *container)
|
||||
: SFTKException(container) {}
|
||||
|
||||
const char *Container::NotAWindowObj::what() const noexcept
|
||||
{
|
||||
static char msg[] = "sftk::Container 0x********_********: Not a sftk::Window.";
|
||||
SFTKException::formatAddress(msg, sizeof(msg));
|
||||
return msg;
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
#include <window.hpp>
|
||||
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include <gtypes.hpp>
|
||||
#include <containers/container.hpp>
|
||||
|
||||
using namespace sftk;
|
||||
|
||||
Window &Window::create(int width, int height, std::wstring name)
|
||||
{
|
||||
return *new Window(width, height, name);
|
||||
}
|
||||
|
||||
Window::Window(int width, int height, std::wstring name)
|
||||
: Container(vec(0.f, 0.f), vec((float)width, (float)height), true),
|
||||
sfwindow(sf::VideoMode(width, height), name),
|
||||
running(new bool(true))
|
||||
{
|
||||
if (Container::getRoot().get())
|
||||
throw WindowMultipleConstructed(this);
|
||||
Container::getRoot(this);
|
||||
}
|
||||
|
||||
void Window::exec()
|
||||
{
|
||||
while (*running)
|
||||
{
|
||||
sf::Event event;
|
||||
bool event_occured = false;
|
||||
while (sfwindow.pollEvent(event))
|
||||
{
|
||||
event_occured = true;
|
||||
dispatchEvent(event);
|
||||
switch (event.type)
|
||||
{
|
||||
case sf::Event::Closed:
|
||||
*running = false;
|
||||
sfwindow.close();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (event_occured || hasInternalChange())
|
||||
{
|
||||
update();
|
||||
sfwindow.display();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Window::setSize(sf::Vector2u size)
|
||||
{
|
||||
sfwindow.setSize(size);
|
||||
Container::setSize(vec((float)size.x, (float)size.y));
|
||||
}
|
||||
|
||||
bool Window::isRoot() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
sf::Vector2f &Window::getPosition() const
|
||||
{
|
||||
auto _pos = sfwindow.getPosition();
|
||||
auto pos = vec((float)_pos.x, (float)_pos.y);
|
||||
v2f_dumpst->push_back(pos);
|
||||
return v2f_dumpst->back();
|
||||
}
|
||||
|
||||
sf::RenderWindow &Window::windowSFWindow()
|
||||
{
|
||||
return sfwindow;
|
||||
}
|
||||
|
||||
Window::WindowMultipleConstructed::WindowMultipleConstructed(Window *window)
|
||||
: SFTKException(window) {}
|
||||
|
||||
const char *Window::WindowMultipleConstructed::what() const noexcept
|
||||
{
|
||||
static char msg[] = "sftk::Window 0x********_********: Multiply constructed in one thread.";
|
||||
SFTKException::formatAddress(msg, sizeof(msg));
|
||||
return msg;
|
||||
}
|
Loading…
Reference in New Issue