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