Refactor core

This commit is contained in:
NaiJi ✨ 2021-12-29 17:59:18 +03:00
parent ac88cd9dfa
commit 833dd2b781
168 changed files with 3301 additions and 2614 deletions

2
.gitignore vendored
View File

@ -2,7 +2,7 @@
# ----------------------------------------------------------------------------
build
SFML*
SFML-*
*.user
*CMakeFiles*
*Makefile

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.5)
cmake_minimum_required(VERSION 3.13)
project(project-kyoku LANGUAGES CXX)
@ -16,38 +16,25 @@ set(CMAKE_THREAD_LIBS_INIT "-lpthread")
set(CMAKE_USE_PTHREADS_INIT 1)
set(THREADS_PREFER_PTHREAD_FLAG ON)
file(GLOB_RECURSE SOURCES "src/main.cpp" "src/application/*.cpp" "src/application/*.h")
include_directories(${CMAKE_SOURCE_DIR}/include)
file(GLOB_RECURSE SOURCES "src/main.cpp")
add_executable(project-kyoku ${SOURCES})
option(SFML_BUILT "SFML_BUILT" OFF)
if(SFML_BUILT)
set(SFML_LIB_DIR
${CMAKE_SOURCE_DIR}/SFML-2.5.1/lib/libsfml-graphics.so.2.5
${CMAKE_SOURCE_DIR}/SFML-2.5.1/lib/libsfml-system.so.2.5
${CMAKE_SOURCE_DIR}/SFML-2.5.1/lib/libsfml-window.so.2.5
${CMAKE_SOURCE_DIR}/SFML-2.5.1/lib/libsfml-audio.so.2.5)
set(SFML_INCL_DIR ${CMAKE_SOURCE_DIR}/SFML-2.5.1/include)
target_link_libraries(project-kyoku ${SFML_LIB_DIR})
else()
find_package(SFML REQUIRED graphics window system)
include_directories(${SFML_INCL_DIR} ${CMAKE_SOURCE_DIR}/include)
target_link_libraries(project-kyoku sfml-system sfml-audio sfml-graphics sfml-network)
endif()
include_directories(${SFML_INCL_DIR} ${CMAKE_SOURCE_DIR}/include)
SET(CMAKE_INSTALL_PREFIX /)
# When new game modes appear, aggregate them into a ONE subdirectory
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modes/classicmode/CMakeLists.txt")
add_subdirectory(modes/classicmode)
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/modes/classicmode/CMakeLists.txt")
add_subdirectory(src/modes/classicmode)
target_link_libraries(project-kyoku classicmode)
endif()
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tools/CMakeLists.txt")
add_subdirectory(tools)
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/tools/CMakeLists.txt")
add_subdirectory(src/tools)
target_link_libraries(project-kyoku tools)
endif()
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/core/CMakeLists.txt")
add_subdirectory(core)
target_link_libraries(project-kyoku core)
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/application/CMakeLists.txt")
add_subdirectory(src/application)
target_link_libraries(project-kyoku application)
endif()
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/impl/CMakeLists.txt")
add_subdirectory(src/impl)
target_link_libraries(project-kyoku impl)
endif()

View File

@ -1,15 +0,0 @@
cmake_minimum_required(VERSION 2.8.8)
project(core)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
include_directories(${CMAKE_SOURCE_DIR}/include)
file(GLOB_RECURSE HEADERS "shared/*.h")
file(GLOB_RECURSE SOURCES "src/*.cpp")
add_library(core STATIC ${SOURCES} ${HEADERS})
target_include_directories(core PRIVATE ${CMAKE_SOURCE_DIR}/tools/shared)
target_link_libraries(core tools)
target_include_directories(project-kyoku PRIVATE ${CMAKE_SOURCE_DIR}/core/shared)

View File

@ -1,10 +0,0 @@
#pragma once
#include <SFML/Window/Event.hpp>
#include "tools/mathutils.h"
struct PlayerInput
{
microsec timestamp;
sf::Event event;
};

View File

@ -1,10 +0,0 @@
#pragma once
#include <SFML/System/Time.hpp>
#include "tools/mathutils.h"
struct UpdateData
{
const microsec timestamp;
const sf::Time dt;
};

37
include/core/area.h Normal file
View File

@ -0,0 +1,37 @@
#pragma once
#include <type_traits>
#include "core/point.h"
#include "core/vector.h"
namespace kku
{
template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
struct Area
{
T left = 0;
T top = 0;
T width = 0;
T height = 0;
inline kku::Point position() const noexcept
{
return kku::Point{static_cast<float>(left),
static_cast<float>(top) };
}
inline void moveBy(const kku::Vector2<T>& vector)
{
top += vector.second;
left += vector.first;
}
inline bool contains(const kku::Point& point) const
{
return point.x >= left ; // debug it when on computer
}
};
}

View File

@ -1,19 +1,24 @@
#pragma once
#include "tools/mathutils.h"
#include "core/time.h"
namespace kku
{
struct BPMSection
{
int bpm = 120; // Hi, osu
int fraction = 2;
unsigned int bpm = 120; // Hi, osu
unsigned int fraction = 2;
microsec offset_start = 0;
microsec interval = 0;
};
struct BPMSectionCompt
struct BPMSectionComparator
{
bool operator()(const BPMSection& lhs, const BPMSection& rhs) const noexcept
{
return lhs.offset_start < rhs.offset_start;
}
};
}

14
include/core/color.h Normal file
View File

@ -0,0 +1,14 @@
#pragma once
namespace kku
{
struct Color
{
unsigned char red = 0;
unsigned char green = 0;
unsigned char blue = 0;
unsigned char alpha = 0;
};
}

View File

@ -0,0 +1,26 @@
#pragma once
#include <memory>
#include "core/music.h"
#include "core/text.h"
#include "core/resourceholder.h"
#include "core/rectangle.h"
#include "core/vector.h"
#include "core/line.h"
namespace kku
{
class CoreFactory
{
public:
virtual ~CoreFactory() = default;
virtual std::shared_ptr<kku::Music> getMusic() const = 0;
virtual std::shared_ptr<kku::Text> getText(kku::Font::Id id) const = 0;
virtual std::shared_ptr<kku::Rectangle> getRectangle() const = 0;
virtual std::shared_ptr<kku::Line> getLine() const = 0;
virtual kku::Vector2<std::size_t> getRenderSize() const = 0;
};
}

View File

@ -1,26 +1,31 @@
#pragma once
#include <set>
#include "core/inputtype.h"
#include <algorithm>
#include "core/gameevent.h"
#include "core/updatedata.h"
#include "core/bpmsection.h"
namespace kku
{
class Editor
{
public:
virtual ~Editor() = default;
virtual void input(PlayerInput&& inputdata) = 0;
virtual void input(GameEvent&& input) = 0;
virtual void update(UpdateData&& updatedata) = 0;
virtual void display() const = 0;
virtual void recalculate(const microsec& timestamp) = 0;
void setBPMSections(const std::set<BPMSection, BPMSectionCompt>& sections) noexcept
void setBPMSections(const std::set<BPMSection, BPMSectionComparator>& sections) noexcept
{
_bpm_sections = sections;
}
void setBPMSections(std::set<BPMSection, BPMSectionCompt>&& sections) noexcept
void setBPMSections(std::set<BPMSection, BPMSectionComparator>&& sections) noexcept
{
_bpm_sections = std::move(sections);
}
@ -77,5 +82,7 @@ public:
}
protected:
std::set<BPMSection, BPMSectionCompt> _bpm_sections;
std::set<BPMSection, BPMSectionComparator> _bpm_sections;
};
}

View File

@ -1,15 +1,20 @@
#pragma once
#include "core/inputtype.h"
#include "core/gameevent.h"
#include "core/updatedata.h"
namespace kku
{
class Game
{
public:
virtual ~Game() = default;
virtual void run() = 0;
virtual void input(PlayerInput&& inputdata) = 0;
virtual void input(GameEvent&& inputdata) = 0;
virtual void update(UpdateData&& updatedata) = 0;
virtual void display() const = 0;
};
}

15
include/core/gameevent.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
#include "core/systemevent.h"
#include "core/time.h"
namespace kku
{
struct GameEvent
{
const microsec timestamp = 0;
const SystemEvent event;
};
}

18
include/core/line.h Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include "core/point.h"
#include "core/color.h"
namespace kku
{
class Line
{
public:
virtual ~Line() = default;
virtual void setPosition(const kku::Point& p1, const kku::Point& p2) = 0;
virtual void setColor(const kku::Color& c1, const kku::Color& c2) = 0;
virtual void display() = 0;
};
}

32
include/core/music.h Normal file
View File

@ -0,0 +1,32 @@
#pragma once
#include <string>
#include "core/time.h"
namespace kku
{
class Music
{
public:
virtual ~Music() = default;
virtual bool open(const std::string& filepath) = 0;
virtual void play() = 0;
virtual void pause() = 0;
virtual void stop() = 0;
virtual bool isPlaying() const = 0;
virtual void setVolume(float volume) = 0;
virtual void setOffset(const kku::microsec& offset) = 0;
virtual void moveOffset(const kku::microsec& delta) = 0;
virtual kku::microsec fetchOffset() = 0;
virtual kku::microsec getDuration() const = 0;
};
}

View File

@ -1,6 +1,10 @@
#pragma once
#include "core/inputtype.h"
#include "core/time.h"
#include "core/gameevent.h"
namespace kku
{
class Note
{
@ -16,34 +20,40 @@ public:
virtual bool isInGame() const = 0;
virtual bool shouldRemove() const = 0;
const microsec& offset() const noexcept
virtual void input(kku::GameEvent&& input) = 0;
inline const microsec& getPerfectOffset() const noexcept
{
return _perfect_offset;
}
bool operator<(const Note& note) const
{
return (_perfect_offset < note._perfect_offset);
return _perfect_offset < note._perfect_offset;
}
bool operator==(const Note& note) const
{
return (_perfect_offset == note._perfect_offset);
return _perfect_offset == note._perfect_offset;
}
bool operator>(const Note& note) const
{
return (_perfect_offset > note._perfect_offset);
return _perfect_offset > note._perfect_offset;
}
protected:
microsec _perfect_offset;
};
struct NotePtrCompt
struct NotePtrComparator
{
bool operator()(const Note* lhs, const Note* rhs) const noexcept
{
return lhs->offset() < rhs->offset();
return lhs->getPerfectOffset() < rhs->getPerfectOffset();
}
};
}

46
include/core/point.h Normal file
View File

@ -0,0 +1,46 @@
#pragma once
namespace kku
{
struct Point
{
float x;
float y;
constexpr inline explicit Point() noexcept :
x(0.), y(0.)
{}
constexpr inline explicit Point(int x, int y) noexcept :
x(x), y(y)
{}
constexpr inline explicit Point(float x, float y) noexcept :
x(x), y(y)
{}
constexpr inline Point operator+(const Point& right) const noexcept
{
return Point{right.x + x, right.y + y};
}
constexpr inline Point operator-(const Point& right) const noexcept
{
return Point{right.x - x, right.y - y};
}
inline void moveBy(float x, float y) noexcept
{
this->x += x;
this->y += y;
}
inline void scaleBy(float factor) noexcept
{
x *= factor;
y *= factor;
}
};
}

View File

@ -1,7 +1,4 @@
#ifndef PRECISIONEVALUATOR_H
#define PRECISIONEVALUATOR_H
#include "tools/mathutils.h"
#pragma once
#include <numeric>
#include <type_traits>
@ -9,6 +6,11 @@
#include <cmath>
#include <iostream>
#include "core/time.h"
namespace kku
{
template<typename Grade, typename = std::enable_if_t<std::is_enum<Grade>::value>>
class PrecisionEvaluator
{
@ -32,11 +34,12 @@ public:
&& music_play_offset < _end_handling_offset;
}
inline Grade calculatePrecision(microsec odds) const noexcept
Grade calculatePrecision(microsec odds) const
{
microsec shift_from_perfect = std::abs(odds - offset());
std::cout << "Shift " << ((odds > _offset) ? "late: " : "early: ") << shift_from_perfect << "\n";
std::cout << "Shift " << ((odds > _offset) ? "late: " : "early: ")
<< shift_from_perfect << "\n";
std::size_t raw_grade;
for (raw_grade = 0; raw_grade < _intervals.size(); ++raw_grade)
@ -63,4 +66,4 @@ private:
const std::vector<microsec> _intervals;
};
#endif // PRECISIONEVALUATOR_H
}

26
include/core/rectangle.h Normal file
View File

@ -0,0 +1,26 @@
#pragma once
#include "core/area.h"
#include "core/color.h"
namespace kku
{
class Rectangle
{
public:
virtual ~Rectangle() = default;
virtual void setRect(const Area<float>& rect) = 0;
virtual Area<float> getRect() const = 0;
virtual void setPosition(const Point& position) = 0;
virtual Point getPosition() const = 0;
virtual void move(const kku::Vector2<float>& delta) = 0;
virtual void setColor(const Color& color) = 0;
virtual bool contains(const kku::Point& position) const = 0;
virtual void display() = 0;
};
}

View File

@ -0,0 +1,35 @@
#pragma once
#include <memory>
#include <map>
namespace kku
{
template <typename Resource, typename Id>
class ResourceHolder
{
public:
inline void load(Id id, std::unique_ptr<Resource>&& resource) noexcept
{
_resources[id] = std::move(resource);
}
inline const std::shared_ptr<Resource>& get(Id id) const
{
return _resources.find(id)->second;
}
private:
std::map<Id, std::shared_ptr<Resource>> _resources;
};
namespace Font
{
enum class Id
{
GUI
};
}
}

View File

@ -1,5 +1,8 @@
#pragma once
namespace kku
{
class Sprite
{
public:
@ -7,3 +10,5 @@ public:
virtual void reset() = 0;
virtual void display() const = 0;
};
}

View File

@ -4,6 +4,9 @@
#include <stack>
#include <map>
namespace kku
{
template<typename Type, class SpriteFactory, class Sprite,
typename = std::enable_if_t<std::is_enum<Type>::value>>
class SpriteContainer
@ -56,3 +59,5 @@ private:
std::size_t _poll_reserve_size;
};
}

View File

@ -0,0 +1,65 @@
#pragma once
#include <variant>
#include "core/point.h"
namespace kku
{
struct SystemEvent
{
enum class Type
{
None = 0,
Resize = 1,
KeyPress = 2,
KeyRelease = 3,
MouseWheelScroll = 4,
MouseMove = 5,
MousePress = 6,
MouseRelease = 7
};
struct Size
{
std::size_t width = 0;
std::size_t height = 0;
};
struct Key
{
char view = char(0);
bool alt = false;
bool control = false;
bool shift = false;
};
struct Mouse
{
Point position;
bool scrolled_up = false;
enum class Button
{
None = 0,
Wheel = 1,
Left = 2,
Right = 3
};
Button button = Button::Left;
};
struct None
{};
Type type = Type::None;
std::variant<Size, Key, Mouse, None> data;
};
}

24
include/core/text.h Normal file
View File

@ -0,0 +1,24 @@
#pragma once
#include <string>
#include "core/color.h"
#include "core/point.h"
#include "core/vector.h"
namespace kku
{
class Text
{
public:
virtual ~Text() = default;
virtual void setString(const std::string& string) = 0;
virtual void setCharacterSize(std::size_t pixels) = 0;
virtual void setPosition(const Point& point) = 0;
virtual void move(const kku::Vector2<float>& delta) = 0;
virtual void setColor(const Color& color) = 0;
virtual void display() = 0;
};
}

22
include/core/time.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
namespace kku
{
using microsec = long long;
struct TimeRange
{
const microsec begin = 0;
const microsec end = 0;
constexpr inline explicit TimeRange() noexcept :
begin(0), end(0)
{}
constexpr inline explicit TimeRange(microsec x, microsec y) noexcept :
begin(x), end(y)
{}
};
}

View File

@ -3,11 +3,13 @@
#include <set>
#include <memory>
#include <algorithm>
#include <iostream>
#include "tools/mathutils.h"
#include "core/time.h"
#include "core/note.h"
namespace kku
{
template <class TNote, class = std::enable_if_t<std::is_base_of<Note, TNote>::value>>
class Timeline
{
@ -29,7 +31,7 @@ public:
while (!isExpired(head_iterator))
{
if ((*head_iterator)->offset() >= offset)
if ((*head_iterator)->getPerfectOffset() >= offset)
{
Iterator pre_head = head_iterator;
--pre_head;
@ -48,7 +50,7 @@ public:
}
}
void setNotes(const std::set<TNote*, NotePtrCompt>& notes)
void setNotes(const std::set<TNote*, NotePtrComparator>& notes)
{
_timeline = std::move(notes);
@ -65,7 +67,7 @@ public:
update(_current_offset);
}
void insertNotes(const std::set<TNote*, NotePtrCompt>& notes)
void insertNotes(const std::set<TNote*, NotePtrComparator>& notes)
{
_timeline.insert(notes.begin(), notes.end());
recalculate(_current_offset);
@ -100,7 +102,7 @@ public:
return_note = note_iterator;
break;
}
else if (note->offset() > music_offset)
else if (note->getPerfectOffset() > music_offset)
break;
++note_iterator;
@ -114,7 +116,7 @@ public:
return std::find_if(_timeline.begin(), _timeline.end(),
[music_offset](const auto& note)
{
return note->offset() == music_offset;
return note->getPerfectOffset() == music_offset;
});
}
@ -134,14 +136,14 @@ public:
}
private:
std::set<TNote*, NotePtrCompt> _timeline;
std::set<TNote*, NotePtrComparator> _timeline;
microsec _current_offset;
inline void updateTopNote(const microsec& music_offset) noexcept
{
const auto& top_note = *_top_note;
bool already_played = top_note->offset() < music_offset
bool already_played = top_note->getPerfectOffset() < music_offset
&& !top_note->isActive(music_offset);
if (already_played)
@ -150,3 +152,7 @@ private:
Iterator _top_note;
};
}

16
include/core/updatedata.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include "core/time.h"
namespace kku
{
struct UpdateData
{
const microsec timestamp;
const microsec dt;
};
}

22
include/core/vector.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include <utility>
namespace kku
{
/* Meaning an element of a vector space in math.
* Don't mistake for std::vector<T>
* For now we don't need it as a special class,
* so let it be a wrapper. */
template <typename T>
using Vector2 = std::pair<T, T>;
template <typename T>
inline constexpr auto makeVector(T&& l, T&& r) -> Vector2<T>
{
return std::make_pair(std::forward<T>(l), std::forward<T>(r));
}
}

View File

@ -1,35 +0,0 @@
#pragma once
#include <stack>
#include <memory>
#include <functional>
#include <SFML/Window/Event.hpp>
#include <SFML/Graphics/Drawable.hpp>
#include <SFML/Graphics/Rect.hpp>
class GUIState : public sf::Drawable
{
public:
enum Tag {
SPLASH_SCREEN,
MAIN_MENU,
GAME_PICKER,
GAME,
EDITOR_PICKER,
EDITOR,
SETTINGS,
AMOUNT
};
virtual ~GUIState() = default;
virtual void input(const sf::Event& event) = 0;
virtual void update(const sf::Time& dt) = 0;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override = 0;
virtual void enter(sf::Vector2u&& render_size) = 0;
virtual void leave() = 0;
};

View File

@ -1,24 +0,0 @@
cmake_minimum_required(VERSION 2.8.8)
project(classicmode)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
include_directories(${CMAKE_SOURCE_DIR}/include)
file(GLOB_RECURSE HEADERS "shared/*.h" )
file(GLOB_RECURSE SOURCES "editor/*.h" "editor/*.cpp"
"graphics/*.h" "graphics/*.cpp"
"game/*.h" "game/*.cpp"
"sfml/*.h" "sfml/*.cpp"
"./classicfactory.cpp")
add_library(classicmode STATIC ${SOURCES} ${HEADERS})
target_include_directories(classicmode PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_include_directories(classicmode PRIVATE ${CMAKE_SOURCE_DIR}/tools/shared)
target_include_directories(classicmode PRIVATE ${CMAKE_SOURCE_DIR}/core/shared)
target_link_libraries(classicmode tools core)
target_include_directories(project-kyoku PRIVATE ${CMAKE_SOURCE_DIR}/modes/classicmode/shared)

View File

@ -1,37 +0,0 @@
#pragma once
#include <memory>
#include "core/editor.h"
#include "core/timeline.h"
#include "game/classicnote.h"
#include "classicmode/classicactions.h"
class ClassicGraphicsManager;
class ClassicEditor : public Editor
{
public:
explicit ClassicEditor(const std::shared_ptr<Timeline<ClassicNote>>& timeline,
const std::shared_ptr<ClassicGraphicsManager>& graphics_manager);
virtual void input(PlayerInput&& inputdata) override;
virtual void update(UpdateData&& updatedata) override;
virtual void display() const override;
virtual void recalculate(const microsec& timestamp) override;
void selectNoteType(Type type) noexcept;
private:
inline microsec adjustOffset(microsec offset) const noexcept;
Context _context;
const std::shared_ptr<Timeline<ClassicNote>> _timeline;
const std::shared_ptr<ClassicGraphicsManager> _graphics_manager;
Type _selected_type;
microsec _current_time;
microsec _scroll_step;
};

View File

@ -1,41 +0,0 @@
#include "mockclassicnote.h"
#include "graphics/classicgraphicsmanager.h"
#include "graphics/animations/classicanimationscenario.h"
MockClassicNote::MockClassicNote(MockArrowNoteInitializer&& init) :
ClassicNote({nullptr, {}, init.initializer.perfect_offset}),
_state(State::NONE),
_context(init.initializer.context)
{
_elements.resize(init.elements.size());
for (std::size_t i = 0; i < _elements.size(); ++i)
{
_elements[i].coordinates = init.elements[i].coordinates;
_elements[i].type = init.elements[i].type;
}
}
void MockClassicNote::putToGame()
{
_state = State::FLYING;
}
void MockClassicNote::update(const microsec &music_offset)
{
switch (_state)
{
default: return;
break;
case State::FLYING:
if (music_offset > offset())
_state = State::DEAD;
break;
}
for (auto& element : _elements)
if (element.animations[_state])
element.animations[_state]->update(music_offset);
}

View File

@ -1,28 +0,0 @@
#pragma once
#include <memory>
#include <array>
#include "mockelement.h"
#include "game/classicnote.h"
#include "initializers/mockarrownoteinitializer.h"
class MockClassicNote : public ClassicNote
{
public:
explicit MockClassicNote(MockArrowNoteInitializer&& init);
virtual ~MockClassicNote() override = default;
virtual void putToGame() override;
virtual void update(const microsec &music_offset) override;
virtual void input(PlayerInput&& inputdata) override;
virtual void display(const ClassicGraphicsManager * const manager) const override;
virtual void setGraphics(ClassicGraphicsManager * const manager, TimeRange&& range) override;
private:
std::vector<MockElement> _elements;
State _state;
const Context *_context;
};

View File

@ -1,21 +0,0 @@
#pragma once
#include "classicmode/classicactions.h"
#include "tools/mathutils.h"
#include <vector>
#include <memory>
#include <array>
class ClassicSprite;
class ClassicAnimationScenario;
struct MockElement
{
std::shared_ptr<ClassicSprite> sprite;
std::array<std::shared_ptr<ClassicAnimationScenario>, 4> animations;
Type type = Type::NONE;
Coordinates coordinates;
std::vector<Coordinates> falling_curve_interpolation;
};

View File

@ -1,116 +0,0 @@
#include "classicgame.h"
#include "classicnote.h"
#include "classicmapcreator.h"
#include "graphics/classicscenegraphicsmanager.h"
#include "holdmanager.h"
ClassicGame::ClassicGame(const std::shared_ptr<Timeline<ClassicNote>>& timeline,
const std::shared_ptr<ClassicGraphicsManager>& graphics_manager) :
_timeline(timeline),
_graphics_manager(graphics_manager),
_hold_manager(std::make_unique<HoldManager>())
{
_slap_buffer.loadFromFile("Tick.ogg");
_slap.setBuffer(_slap_buffer);
_slap.setVolume(50);
_keys_to_buttons =
{
{sf::Keyboard::Up, Type::UP}, // Load from settings
{sf::Keyboard::Right, Type::RIGHT},
{sf::Keyboard::Down, Type::DOWN},
{sf::Keyboard::Left, Type::LEFT},
{sf::Keyboard::W, Type::UP},
{sf::Keyboard::D, Type::RIGHT},
{sf::Keyboard::S, Type::DOWN},
{sf::Keyboard::A, Type::LEFT},
{sf::Keyboard::E, Type::SLIDER_RIGHT},
{sf::Keyboard::Q, Type::SLIDER_LEFT}
};
_buttons_to_pressed_actions=
{
{Type::UP, Action::PRESS_UP},
{Type::RIGHT, Action::PRESS_RIGHT},
{Type::DOWN, Action::PRESS_DOWN},
{Type::LEFT, Action::PRESS_LEFT},
{Type::SLIDER_RIGHT, Action::PRESS_SLIDER_RIGHT},
{Type::SLIDER_LEFT, Action::PRESS_SLIDER_LEFT}
};
_buttons_to_released_actions=
{
{Type::UP, Action::RELEASE_UP},
{Type::RIGHT, Action::RELEASE_RIGHT},
{Type::DOWN, Action::RELEASE_DOWN},
{Type::LEFT, Action::RELEASE_LEFT},
{Type::SLIDER_RIGHT, Action::RELEASE_SLIDER_RIGHT},
{Type::SLIDER_LEFT, Action::RELEASE_SLIDER_LEFT}
};
}
ClassicGame::~ClassicGame()
{}
void ClassicGame::run()
{
_context.hold_manager = _hold_manager;
auto beatmap = classic::createBeatmap("aa", _context);
_timeline->setNotes(beatmap.notes);
}
void ClassicGame::input(PlayerInput&& inputdata)
{
switch (inputdata.event.type)
{
default:
return;
break;
case sf::Event::KeyPressed:
{
auto note_it = _timeline->getActiveNote(inputdata.timestamp);
if (!_timeline->isExpired(note_it))
{
auto note = (*note_it);
note->input(std::move(inputdata));
_slap.play();
}
}
break;
case sf::Event::KeyReleased:
{
_hold_manager->checkRelease(inputdata.event.key.code);
}
break;
}
}
void ClassicGame::update(UpdateData&& updatedata)
{
// UNCOMMENT TO TEST AUTOPLAY
auto note_it = _timeline->getActiveNote(updatedata.timestamp);
if (!_timeline->isExpired(note_it) && updatedata.timestamp >= (*note_it)->offset())
{
auto note = (*note_it);
note->input(PlayerInput{updatedata.timestamp, sf::Event{}});
_slap.play();
}
_timeline->update(updatedata.timestamp);
_graphics_manager->update(updatedata.timestamp);
}
void ClassicGame::display() const
{
_graphics_manager->display();
}

View File

@ -1,37 +0,0 @@
#include "classicdyinganimationscenario.h"
#include "graphics/classicsprite.h"
void ClassicDyingAnimationScenario::launch(const std::shared_ptr<ClassicSprite> sprite, const microsec& time_begin, const microsec &time_end)
{
_sprite = sprite;
_time_begin = time_begin;
_time_end = time_end;
_sprite->setColor(sf::Color(140, 140, 140));
_sprite->setTrailColor(sf::Color(0, 0, 0, 0));
_sprite->setTrailCoordinates(Coordinates(0, 0));
}
void ClassicDyingAnimationScenario::update(const microsec& music_offset)
{
(void) music_offset;
auto fill_color = _sprite->color();
if (fill_color.a == 0)
{
fill_color.a = 0;
_sprite->setColor(fill_color);
return;
}
auto new_alpha = fill_color.a - 15;
fill_color.a = new_alpha < 0 ? 0 : new_alpha;
_sprite->setColor(fill_color);
}
bool ClassicDyingAnimationScenario::isDone() const
{
return _sprite->color().a == 0;
}

View File

@ -1,55 +0,0 @@
#include "classicflyinganimationscenario.h"
#include "graphics/classicsprite.h"
void ClassicFlyingAnimationScenario::launch(const std::shared_ptr<ClassicSprite> sprite, const microsec& time_begin, const microsec &time_end)
{
_sprite = sprite;
_time_begin = time_begin;
_time_end = time_end;
_percentage = ((_time_end - _time_begin) * 0.01);
}
float ClassicFlyingAnimationScenario::getPoint(float n1, float n2, float perc) const
{
float diff = n2 - n1;
return n1 + ( diff * perc );
}
void ClassicFlyingAnimationScenario::update(const microsec& music_offset)
{
const auto crd = _sprite->coordinates();
auto update_time = music_offset - _time_begin;
float i = update_time / _percentage * 0.01;
float xa = getPoint( crd.x + 20. , crd.x + 90. , i );
float ya = getPoint( crd.y - 600. , crd.y - 150. , i );
float xb = getPoint( crd.x + 90. , crd.x , i );
float yb = getPoint( crd.y - 150. , crd.y , i );
_sprite->setTrailCoordinates(Coordinates(getPoint( xa , xb , i ), getPoint( ya , yb , i )));
bool pastPerfectScore = (i >= 1);
if (pastPerfectScore)
fadeTrailSprite();
}
bool ClassicFlyingAnimationScenario::isDone() const
{
return false;
}
void ClassicFlyingAnimationScenario::fadeTrailSprite() const
{
auto fill_color = _sprite->trailColor();
if (fill_color.a == 0)
return;
auto new_alpha = fill_color.a - 35;
fill_color.a = new_alpha < 0 ? 0 : new_alpha;
_sprite->setTrailColor(fill_color);
}

View File

@ -1,37 +0,0 @@
#pragma once
#include "game/classicnote.h"
#include "graphics/classicgraphicsmanager.h"
#include "core/timeline.h"
class ClassicSprite;
class ClassicSceneGraphicsManager : public ClassicGraphicsManager
{
public:
explicit ClassicSceneGraphicsManager(const std::shared_ptr<Timeline<ClassicNote>>& timeline,
const std::shared_ptr<ClassicSpriteFactory>& factory,
const microsec& visibility_offset);
virtual void display() const override;
virtual void update(const microsec& offset) override;
virtual void display(const std::vector<ArrowElement>& elements) const override;
virtual void setGraphics(std::vector<ArrowElement>& elements, TimeRange&& range) override;
protected:
using Iterator = Timeline<ClassicNote>::Iterator;
Iterator _first;
Iterator _last;
const std::shared_ptr<Timeline<ClassicNote>> _timeline;
inline bool nothingToDraw() const noexcept;
inline bool isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const noexcept;
//inline sf::VertexArray makeLine(const Coordinates& c1, const Coordinates& c2) const;
void fetchFirstNote(const microsec& offset);
void fetchLastNote(const microsec& offset);
void updateVisibleNotes(const microsec& offset);
};

View File

@ -1,65 +0,0 @@
#include "classicsprite.h"
#include <SFML/Graphics/RenderTarget.hpp>
ClassicSprite::ClassicSprite(const std::shared_ptr<sf::RenderTarget> &render_target,
const sf::RectangleShape& shape) :
_prototype(shape),
_shape(shape),
_trail(shape),
_render_target(render_target)
{}
void ClassicSprite::reset()
{
_shape.setPosition(0, 0);
_trail.setPosition(0, 0);
_shape = _prototype;
_trail = _prototype;
}
void ClassicSprite::setCoordinates(const Coordinates& coordinates)
{
_shape.setPosition(coordinates.x, coordinates.y);
}
void ClassicSprite::setTrailCoordinates(const Coordinates &coordinates)
{
_trail.setPosition(coordinates.x, coordinates.y);
}
Coordinates ClassicSprite::coordinates() const
{
return Coordinates(_shape.getPosition().x, _shape.getPosition().y);
}
Coordinates ClassicSprite::trailCoordinates() const
{
return Coordinates(_trail.getPosition().x, _trail.getPosition().y);
}
void ClassicSprite::setColor(const sf::Color& color)
{
_shape.setFillColor(color);
}
void ClassicSprite::setTrailColor(const sf::Color& color)
{
_trail.setFillColor(color);
}
sf::Color ClassicSprite::color() const
{
return _shape.getFillColor();
}
sf::Color ClassicSprite::trailColor() const
{
return _trail.getFillColor();
}
void ClassicSprite::display() const
{
_render_target->draw(_shape);
_render_target->draw(_trail);
}

View File

@ -1,34 +0,0 @@
#pragma once
#include <memory>
#include "tools/mathutils.h"
#include "sprite.h"
#include <SFML/Graphics/RectangleShape.hpp>
#include <SFML/Graphics/RenderTarget.hpp>
class ClassicSprite : public Sprite
{
public:
explicit ClassicSprite(const std::shared_ptr<sf::RenderTarget>& render_target,
const sf::RectangleShape& shape);
virtual void reset() override;
virtual void display() const override;
void setCoordinates(const Coordinates &coordinates);
void setTrailCoordinates(const Coordinates &coordinates);
Coordinates coordinates() const;
Coordinates trailCoordinates() const;
void setColor(const sf::Color& color);
void setTrailColor(const sf::Color& color);
sf::Color color() const;
sf::Color trailColor() const;
private:
sf::RectangleShape _prototype;
sf::RectangleShape _shape;
sf::RectangleShape _trail;
const std::shared_ptr<sf::RenderTarget> _render_target;
};

View File

@ -1,14 +0,0 @@
#pragma once
#include "classicactions.h"
#include "core/inputtype.h"
#include "tools/mathutils.h"
#include <vector>
struct ElementInitializer
{
Type type = Type::NONE;
Coordinates coordinates;
std::vector<Coordinates> falling_curve_interpolation;
};

View File

@ -1,14 +0,0 @@
#pragma once
#include <memory>
#include <SFML/Graphics/RenderWindow.hpp>
class Game;
class Editor;
namespace classic
{
std::unique_ptr<Game> initGame(const std::shared_ptr<sf::RenderTarget>& render_target);
std::unique_ptr<Editor> initEditor(const std::shared_ptr<sf::RenderTarget>& render_target);
}

View File

@ -0,0 +1,18 @@
cmake_minimum_required(VERSION 3.13)
project(application)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
include_directories(${CMAKE_SOURCE_DIR}/include)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/shared)
file(GLOB_RECURSE HEADERS "shared/*.h" "include/*.h")
file(GLOB_RECURSE SOURCES "src/*.cpp")
add_library(application STATIC ${SOURCES} ${HEADERS})
target_link_libraries(application tools classicmode)
target_include_directories(application PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_include_directories(application PRIVATE ${CMAKE_SOURCE_DIR}/src/modes/classicmode/shared)
target_include_directories(application PRIVATE ${CMAKE_SOURCE_DIR}/src/tools/shared)
target_include_directories(project-kyoku PRIVATE ${CMAKE_SOURCE_DIR}/src/application/shared)

View File

@ -1,119 +0,0 @@
#include "application.h"
#include "core/inputtype.h"
#include "core/editor.h"
#include "mainmenu.h"
#include "gamestate.h"
#include "editorstate.h"
#include "tools/music.h"
#include "classicmode/classicfactorysfml.h"
#include <iostream>
const sf::Time TIME_PER_FRAME = sf::seconds(1.f / 90.f);
Application::Application() :
_game_window(std::make_unique<sf::RenderWindow>(sf::VideoMode{1280, 720}, "Test", sf::Style::Default))
{
_font_holder.load(Fonts::Id::GUI, "SourceCodePro-Regular.ttf");
_game_window->setFramerateLimit(60);
_game_window->setKeyRepeatEnabled(false);
_game_window->setMouseCursorGrabbed(false);
_game_window->setVerticalSyncEnabled(true);
MainMenu::Callbacks callbacks =
{
[&](){ pushState(GUIState::Tag::GAME); },
[&](){ pushState(GUIState::Tag::EDITOR); }
};
EditorState::Callbacks editor_callbacks = {[&](){ popState(); }};
const auto main_menu = std::make_shared<MainMenu>(std::move(callbacks), _font_holder);
const auto game_state = std::make_shared<GameState>(classic::initGame(_game_window), GameState::Callbacks());
const auto editor = std::make_shared<EditorState>(classic::initEditor(_game_window), std::move(editor_callbacks), _font_holder);
_states[GUIState::Tag::MAIN_MENU] = main_menu;
_states[GUIState::Tag::GAME] = game_state;
_states[GUIState::Tag::EDITOR] = editor;
pushState(GUIState::Tag::MAIN_MENU);
}
void Application::run()
{
_game_window->display();
exec();
}
void Application::exec()
{
sf::Clock timer;
sf::Time time_since_last_update = sf::Time::Zero;
while (_game_window->isOpen())
{
time_since_last_update += timer.restart();
input();
bool isOneFramePassed = time_since_last_update >= TIME_PER_FRAME;
if (isOneFramePassed)
{
time_since_last_update -= TIME_PER_FRAME;
update(time_since_last_update);
draw();
}
}
}
void Application::input()
{
sf::Event event;
while (_game_window->pollEvent(event))
{
switch(event.type)
{
case sf::Event::Closed:
_game_window->close();
break;
default:
_state_stack.back()->input(event);
break;
}
}
}
void Application::update(const sf::Time& dt)
{
_state_stack.back()->update(dt);
}
void Application::draw()
{
_game_window->clear();
for (const auto& state : _state_stack)
_game_window->draw(*state);
_game_window->display();
}
void Application::pushState(GUIState::Tag new_state)
{
if (!_state_stack.empty())
_state_stack.back()->leave();
_state_stack.emplace_back(_states.at(new_state));
_state_stack.back()->enter(_game_window->getSize());
}
void Application::popState()
{
_state_stack.back()->leave();
_state_stack.pop_back();
_state_stack.back()->enter(_game_window->getSize());
}

View File

@ -1,40 +0,0 @@
#pragma once
#include <vector>
#include <memory>
#include <array>
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Graphics/Font.hpp>
#include <SFML/System/Clock.hpp>
#include <SFML/Window/Keyboard.hpp>
#include <SFML/Window/Event.hpp>
#include "core/game.h"
#include "state.h"
#include "tools/music.h"
#include "tools/resourceholder.h"
class Application
{
public:
explicit Application();
void run();
void input();
void update(const sf::Time& dt);
void draw();
private:
std::array<std::shared_ptr<GUIState>, GUIState::Tag::AMOUNT> _states;
std::vector<std::shared_ptr<GUIState>> _state_stack;
std::shared_ptr<sf::RenderWindow> _game_window;
Music _music;
void exec();
void pushState(GUIState::Tag new_state);
void popState();
FontHolder _font_holder;
};

View File

@ -1,41 +0,0 @@
#pragma once
#include "state.h"
#include "tools/music.h"
#include "tools/resourceholder.h"
#include <SFML/Graphics/RenderWindow.hpp>
class BPMCalculator;
class Group;
class Editor;
class EditorState : public GUIState
{
public:
struct Callbacks
{
std::function<void(void)> onLeaveEditorState;
};
explicit EditorState(std::unique_ptr<Editor>&& editor, Callbacks&& callbacks, const FontHolder& font_holder);
virtual ~EditorState() override;
virtual void input(const sf::Event& event) override;
virtual void update(const sf::Time& dt) override;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
virtual void enter(sf::Vector2u&& render_size) override;
virtual void leave() override;
private:
const std::shared_ptr<sf::Font> _font;
Callbacks _callbacks;
Music _music;
std::shared_ptr<BPMCalculator> _bpm_calculator;
std::shared_ptr<Group> _group;
std::unique_ptr<Editor> _editor;
};

View File

@ -1,44 +0,0 @@
#include "gamestate.h"
#include "widgets/button.h"
#include "widgets/group.h"
#include "core/game.h"
GameState::GameState(const std::shared_ptr<Game>& game, Callbacks&& callbacks) :
_game(game),
_onLeaveGameCallback(callbacks.onLeaveGame)
{}
void GameState::input(const sf::Event& event)
{
if (event.key.code == sf::Keyboard::Space && event.type == sf::Event::KeyReleased)
_music.isPaused() ? _music.play() : _music.pause();
_game->input(PlayerInput{_music.fetchOffset(), event});
}
void GameState::update(const sf::Time& dt)
{
_game->update(UpdateData{_music.fetchOffset(), dt});
}
void GameState::draw(sf::RenderTarget &target, sf::RenderStates states) const
{
(void)target; (void)states;
_game->display();
}
void GameState::enter(sf::Vector2u&& render_size)
{
(void)render_size; // We will need this later when I add UI to game state
_game->run();
_music.openFromFile("METEOR.flac");
_music.setVolume(10);
_music.play();
}
void GameState::leave()
{
_onLeaveGameCallback();
}

View File

@ -1,36 +0,0 @@
#pragma once
#include "state.h"
#include "tools/music.h"
#include <SFML/Graphics/RenderWindow.hpp>
class Group;
class Game;
class GameState : public GUIState
{
public:
struct Callbacks
{
std::function<void(void)> onLeaveGame;
};
explicit GameState(const std::shared_ptr<Game>& game, Callbacks&& callbacks);
virtual void input(const sf::Event& event) override;
virtual void update(const sf::Time& dt) override;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
virtual void enter(sf::Vector2u&& render_size) override;
virtual void leave() override;
private:
Music _music;
std::shared_ptr<Game> _game;
std::function<void(void)> _onEnterGameCallback;
std::function<void(void)> _onLeaveGameCallback;
};

View File

@ -0,0 +1,43 @@
#pragma once
#include "application/state.h"
#include "core/corefactory.h"
#include "core/music.h"
class BPMCalculator;
class Group;
namespace kku
{
class Editor;
}
class EditorState : public GUIState
{
public:
struct Callbacks
{
std::function<void(void)> onLeaveEditorState;
};
explicit EditorState(const std::shared_ptr<kku::CoreFactory>& core_factory, std::unique_ptr<kku::Editor>&& editor, Callbacks&& callbacks);
virtual ~EditorState() override;
virtual void input(const kku::SystemEvent& event) override;
virtual void update(const kku::microsec& dt) override;
virtual void display() const override;
virtual void enter() override;
virtual void leave() override;
private:
const Callbacks _callbacks;
const std::shared_ptr<kku::CoreFactory> _core_factory;
std::shared_ptr<kku::Music> _music;
std::shared_ptr<BPMCalculator> _bpm_calculator;
std::shared_ptr<Group> _group;
std::unique_ptr<kku::Editor> _editor;
};

View File

@ -0,0 +1,35 @@
#pragma once
#include "state.h"
#include "core/music.h"
#include "core/game.h"
class Group;
class GameState : public GUIState
{
public:
struct Callbacks
{
std::function<void(void)> onLeaveGame;
};
explicit GameState(const std::shared_ptr<kku::Game>& game, Callbacks&& callbacks);
virtual void input(const kku::SystemEvent& event) override;
virtual void update(const kku::microsec& dt) override;
virtual void display() const override;
virtual void enter() override;
virtual void leave() override;
private:
std::shared_ptr<kku::Music> _music;
std::shared_ptr<kku::Game> _game;
std::function<void(void)> _onEnterGameCallback;
std::function<void(void)> _onLeaveGameCallback;
};

View File

@ -0,0 +1,32 @@
#pragma once
#include "application/state.h"
#include "core/corefactory.h"
class Group;
class MainMenu : public GUIState
{
public:
struct Callbacks
{
std::function<void(void)> onAppendGameState;
std::function<void(void)> onAppendEditorState;
};
explicit MainMenu(const std::shared_ptr<kku::CoreFactory>& factory, Callbacks&& callbacks);
virtual void input(const kku::SystemEvent& event) override;
virtual void update(const kku::microsec& dt) override;
virtual void display() const override;
virtual void enter() override;
virtual void leave() override;
private:
const Callbacks _callbacks;
const std::shared_ptr<kku::CoreFactory> _core_factory;
std::shared_ptr<Group> _buttons;
};

View File

@ -0,0 +1,35 @@
#pragma once
#include <stack>
#include <memory>
#include <functional>
#include "core/systemevent.h"
#include "core/vector.h"
#include "core/time.h"
class GUIState
{
public:
enum Tag {
SPLASH_SCREEN,
MAIN_MENU,
GAME_PICKER,
GAME,
EDITOR_PICKER,
EDITOR,
SETTINGS,
AMOUNT
};
virtual ~GUIState() = default;
virtual void input(const kku::SystemEvent& event) = 0;
virtual void update(const kku::microsec& dt) = 0;
virtual void display() const = 0;
virtual void enter() = 0;
virtual void leave() = 0;
};

View File

@ -1,50 +0,0 @@
#include "mainmenu.h"
#include "widgets/pushbutton.h"
#include "widgets/group.h"
MainMenu::MainMenu(Callbacks&& callbacks, const FontHolder& font_holder) :
_font(font_holder.get(Fonts::Id::GUI)),
_callbacks(std::move(callbacks)),
_buttons(std::make_shared<Group>())
{
}
void MainMenu::input(const sf::Event& event)
{
_buttons->input(event);
}
void MainMenu::update(const sf::Time& dt)
{
_buttons->update(dt);
}
void MainMenu::draw(sf::RenderTarget &target, sf::RenderStates states) const
{
target.draw(*_buttons, states);
}
void MainMenu::enter(sf::Vector2u&& render_size)
{
const float window_width = render_size.x;
const float window_height = render_size.y;
auto button_start = std::make_shared<PushButton>("Start", _font, 48);
button_start->setRect(sf::FloatRect(window_width / 3., window_height / 7., window_width / 3., window_height / 7.));
button_start->setCallback(_callbacks.onAppendGameState);
auto button_editor = std::make_shared<PushButton>("Editor", _font, 48);
button_editor->setRect(sf::FloatRect(window_width / 3., window_height / 7. * 3, window_width / 3., window_height / 7.));
button_editor->setCallback(_callbacks.onAppendEditorState);
_buttons->addChild(button_start);
_buttons->addChild(button_editor);
_buttons->setVisibility();
}
void MainMenu::leave()
{
_buttons->setVisibility(false);
}

View File

@ -1,33 +0,0 @@
#pragma once
#include "state.h"
#include "tools/resourceholder.h"
#include <SFML/Graphics/RenderWindow.hpp>
class Group;
class MainMenu : public GUIState
{
public:
struct Callbacks
{
std::function<void(void)> onAppendGameState;
std::function<void(void)> onAppendEditorState;
};
explicit MainMenu(Callbacks&& callbacks, const FontHolder &font_holder);
virtual void input(const sf::Event& event) override;
virtual void update(const sf::Time& dt) override;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
virtual void enter(sf::Vector2u&& render_size) override;
virtual void leave() override;
private:
const std::shared_ptr<sf::Font> _font;
const Callbacks _callbacks;
std::shared_ptr<Group> _buttons;
};

View File

@ -0,0 +1,32 @@
#pragma once
#include <vector>
#include <memory>
#include <array>
#include "../../include/application/state.h" // HOW? WHY DOESN'T "application/state.h" LINK ON BY ITSELF
#include "core/corefactory.h"
class ClassicFactory;
class Application
{
public:
virtual ~Application() = default;
virtual bool init();
virtual void display() = 0;
virtual void run() = 0;
void input(const kku::SystemEvent& input);
void update(const kku::microsec& dt);
protected:
std::shared_ptr<kku::CoreFactory> _core_factory;
std::shared_ptr<ClassicFactory> _game_factory;
std::array<std::shared_ptr<GUIState>, GUIState::Tag::AMOUNT> _states;
std::vector<std::shared_ptr<GUIState>> _state_stack;
void pushState(GUIState::Tag new_state);
void popState();
};

View File

@ -0,0 +1,61 @@
#include "application/application.h"
#include "core/gameevent.h"
#include "core/editor.h"
#include "application/mainmenu.h"
#include "application/gamestate.h"
#include "application/editorstate.h"
#include "classicmode/classicfactory.h"
bool Application::init()
{
if (!_game_factory || !_core_factory)
return false;
MainMenu::Callbacks callbacks =
{
[&](){ pushState(GUIState::Tag::GAME); },
[&](){ pushState(GUIState::Tag::EDITOR); }
};
EditorState::Callbacks editor_callbacks = {[&](){ popState(); }};
const auto main_menu = std::make_shared<MainMenu>(_core_factory, std::move(callbacks));
const auto game_state = std::make_shared<GameState>(_game_factory->getGame(), GameState::Callbacks());
const auto editor = std::make_shared<EditorState>(_core_factory, _game_factory->getEditor(), std::move(editor_callbacks));
_states[GUIState::Tag::MAIN_MENU] = main_menu;
_states[GUIState::Tag::GAME] = game_state;
_states[GUIState::Tag::EDITOR] = editor;
pushState(GUIState::Tag::MAIN_MENU);
return true;
}
void Application::input(const kku::SystemEvent& event)
{
_state_stack.back()->input(event);
}
void Application::update(const kku::microsec& dt)
{
_state_stack.back()->update(dt);
}
void Application::pushState(GUIState::Tag new_state)
{
if (!_state_stack.empty())
_state_stack.back()->leave();
_state_stack.emplace_back(_states.at(new_state));
_state_stack.back()->enter();
}
void Application::popState()
{
_state_stack.back()->leave();
_state_stack.pop_back();
_state_stack.back()->enter();
}

View File

@ -1,4 +1,4 @@
#include "editorstate.h"
#include "application/editorstate.h"
#include "widgets/button.h"
#include "widgets/group.h"
#include "widgets/menubar.h"
@ -9,36 +9,37 @@
#include "core/editor.h"
#include <iostream>
EditorState::EditorState(std::unique_ptr<Editor>&& editor, Callbacks&& callbacks, const FontHolder& font_holder) :
_font(font_holder.get(Fonts::Id::GUI)),
EditorState::EditorState(const std::shared_ptr<kku::CoreFactory>& core_factory,
std::unique_ptr<kku::Editor>&& editor,
Callbacks&& callbacks) :
_callbacks(std::move(callbacks)),
_core_factory(core_factory),
_editor(std::move(editor))
{}
EditorState::~EditorState()
{}
void EditorState::input(const sf::Event& event)
void EditorState::input(const kku::SystemEvent& event)
{
_group->input(event);
}
void EditorState::update(const sf::Time& dt)
void EditorState::update(const kku::microsec& dt)
{
_group->update(dt);
}
void EditorState::draw(sf::RenderTarget &target, sf::RenderStates states) const
void EditorState::display() const
{
target.draw(*_group, states);
_group->display();
}
void EditorState::enter(sf::Vector2u &&render_size)
void EditorState::enter()
{
_music.openFromFile("METEOR.flac");
_music.setVolume(5);
_music = _core_factory->getMusic();
_music->open("METEOR.flac");
_music->setVolume(5.f);
auto& group = _group;
auto& music = _music;
@ -46,15 +47,15 @@ void EditorState::enter(sf::Vector2u &&render_size)
_bpm_calculator = std::make_shared<BPMCalculator>();
auto& bpm_calculator = _bpm_calculator;
std::shared_ptr<BPMCalculatorWidget> bpm_widget = std::make_shared<BPMCalculatorWidget>(_bpm_calculator, _font);
std::shared_ptr<BPMCalculatorWidget> bpm_widget = std::make_shared<BPMCalculatorWidget>(_bpm_calculator, _core_factory);
auto button_start = std::make_shared<PushButton>("Start", _font);
auto button_stop = std::make_shared<PushButton>("Stop", _font);
auto button_apply = std::make_shared<PushButton>("Apply", _font);
auto button_start = std::make_shared<PushButton>("Start", _core_factory);
auto button_stop = std::make_shared<PushButton>("Stop", _core_factory);
auto button_apply = std::make_shared<PushButton>("Apply", _core_factory);
button_start->setCallback([bpm_calculator, button_start, button_stop, &music]()
{
music.play();
music->play();
bpm_calculator->start();
button_start->setVisibility(false);
button_stop->setVisibility(true);
@ -62,7 +63,7 @@ void EditorState::enter(sf::Vector2u &&render_size)
button_stop->setCallback([bpm_calculator, button_start, button_stop, &music]()
{
music.stop();
music->stop();
bpm_calculator->stop();
button_start->setVisibility(true);
button_stop->setVisibility(false);
@ -70,7 +71,7 @@ void EditorState::enter(sf::Vector2u &&render_size)
button_apply->setCallback([&editor, bpm_calculator]()
{
BPMSection section;
kku::BPMSection section;
const auto& info = bpm_calculator->fetchApproximatedInfo();
section.bpm = info.BPM;
section.interval = info.interval;
@ -84,21 +85,22 @@ void EditorState::enter(sf::Vector2u &&render_size)
bpm_widget_init.stop = button_stop;
bpm_widget_init.apply = button_apply;
bpm_widget_init.start = button_start;
bpm_widget_init.current_time = [&music]() -> microsec { return music.fetchOffset(); };
bpm_widget_init.current_time = [&music]() -> kku::microsec { return music->fetchOffset(); };
bpm_widget->init(std::move(bpm_widget_init));
const auto bpm_widget_callback = [&group, bpm_widget=bpm_widget, &music]()
{
music.stop();
music->stop();
bpm_widget->setVisibility(false);
group->unblock();
};
const float window_width = render_size.x;
const auto render_size = _core_factory->getRenderSize();
const float window_width = render_size.first;
auto menu_bar = std::make_shared<MenuBar>(_font);
auto menu_bar = std::make_shared<MenuBar>(_core_factory);
auto bpm_button = std::make_shared<PushButton>("Calculate BPM", _font);
auto bpm_button = std::make_shared<PushButton>("Calculate BPM", _core_factory);
bpm_button->setCallback([&group, bpm_widget=bpm_widget]()
{
@ -106,29 +108,29 @@ void EditorState::enter(sf::Vector2u &&render_size)
bpm_widget->setVisibility(true);
});
bpm_widget->setRect(sf::FloatRect(render_size.x / 3, render_size.y / 3,
render_size.x / 3, render_size.y / 3));
bpm_widget->setRect(kku::Area<float>{render_size.first / 3.f, render_size.second / 3.f,
render_size.first / 3.f, render_size.second / 3.f});
bpm_widget->addBarButton("X", bpm_widget_callback);
bpm_widget->setVisibility(false);
auto test_menu_2 = std::make_shared<MenuDrop>();
test_menu_2->setRect(sf::FloatRect{0, 0, 200, 27 * 5});
auto test_menu_2 = std::make_shared<MenuDrop>(_core_factory);
test_menu_2->setRect(kku::Area<float>{0., 0., 200., 27. * 5.});
auto test_menu_3 = std::make_shared<MenuDrop>();
test_menu_3->setRect(sf::FloatRect{0, 0, 200, 27 * 5});
auto test_menu_3 = std::make_shared<MenuDrop>(_core_factory);
test_menu_3->setRect(kku::Area<float>{0., 0., 200., 27. * 5.});
auto test_cascade_button = std::make_shared<CascadeMenuButton>("Show submenu", _font);
auto test_cascade_button = std::make_shared<CascadeMenuButton>("Show submenu", _core_factory);
auto test_cascade_button_2 = std::make_shared<CascadeMenuButton>("Show submenu 2", _font);
auto test_cascade_button_2 = std::make_shared<CascadeMenuButton>("Show submenu 2", _core_factory);
auto quit_button = std::make_shared<PushButton>("Quit", _font);
auto quit_button = std::make_shared<PushButton>("Quit", _core_factory);
quit_button->setCallback(_callbacks.onLeaveEditorState);
auto test_menu = std::make_shared<MenuDrop>();
test_menu->setRect(sf::FloatRect{0, 0, 200, 27 * 3});
auto test_menu = std::make_shared<MenuDrop>(_core_factory);
test_menu->setRect(kku::Area<float>{0., 0., 200., 27. * 3.});
menu_bar->setRect(sf::FloatRect(0, 0, window_width, 27));
menu_bar->setRect(kku::Area<float>{0., 0., window_width, 27.});
menu_bar->addRootSubMenu("test", test_menu);
menu_bar->addDependentSubmenu(test_menu_2);
menu_bar->addDependentSubmenu(test_menu_3);
@ -148,28 +150,29 @@ void EditorState::enter(sf::Vector2u &&render_size)
menu_bar->setVisibility(true);
EditorWidget::Callbacks callbacks;
callbacks.onDraw = [&editor](sf::RenderTarget& target, sf::RenderStates states)
callbacks.onDisplay = [&editor]()
{
(void)target; (void)states; // fucking shit i am a retard damn fuck fuck
editor->display();
};
callbacks.onInput = [&editor, &music](const sf::Event& event)
callbacks.onInput = [&editor, &music](const kku::SystemEvent& event)
{
if (event.key.code == sf::Keyboard::Space && event.type == sf::Event::KeyReleased)
music.isPaused() ? music.play() : music.pause();
else if (event.type == sf::Event::MouseWheelScrolled)
if (event.type == kku::SystemEvent::Type::KeyRelease
&& std::get<kku::SystemEvent::Key>(event.data).view == ' ')
music->isPlaying() ? music->pause() : music->play();
else if (event.type == kku::SystemEvent::Type::MouseWheelScroll)
{
music.moveOffset(event.mouseWheelScroll.delta > 0 ? 500000 : -500000);
editor->recalculate(music.fetchOffset());
const auto& up = std::get<kku::SystemEvent::Mouse>(event.data).scrolled_up;
music->moveOffset(up ? 500000 : -500000);
editor->recalculate(music->fetchOffset());
}
else
editor->input(PlayerInput{music.fetchOffset(), event});
editor->input(kku::GameEvent{music->fetchOffset(), event});
};
callbacks.onUpdate = [&editor, &music](const sf::Time& dt)
callbacks.onUpdate = [&editor, &music](const kku::microsec& dt)
{
editor->update(UpdateData{music.fetchOffset(), dt});
editor->update(kku::UpdateData{music->fetchOffset(), dt});
};
auto editor_widget = std::make_shared<EditorWidget>(std::move(callbacks));

View File

@ -0,0 +1,49 @@
#include "application/gamestate.h"
#include "widgets/button.h"
#include "widgets/group.h"
#include "core/game.h"
GameState::GameState(const std::shared_ptr<kku::Game>& game, Callbacks&& callbacks) :
_game(game),
_onLeaveGameCallback(callbacks.onLeaveGame)
{}
void GameState::input(const kku::SystemEvent& event)
{
switch (event.type)
{
default:
break;
case kku::SystemEvent::Type::KeyRelease:
if (std::get<kku::SystemEvent::Key>(event.data).view == ' ')
_music->isPlaying() ? _music->pause() : _music->play();
}
_game->input(kku::GameEvent{_music->fetchOffset(), event});
}
void GameState::update(const kku::microsec& dt)
{
_game->update(kku::UpdateData{_music->fetchOffset(), dt});
}
void GameState::display() const
{
_game->display();
}
void GameState::enter()
{
_game->run();
_music->open("METEOR.flac");
_music->setVolume(10);
_music->play();
}
void GameState::leave()
{
_onLeaveGameCallback();
}

View File

@ -0,0 +1,53 @@
#include "application/mainmenu.h"
#include "widgets/pushbutton.h"
#include "widgets/group.h"
MainMenu::MainMenu(const std::shared_ptr<kku::CoreFactory>& factory, MainMenu::Callbacks&& callbacks) :
_callbacks(std::move(callbacks)),
_core_factory(factory),
_buttons(std::make_shared<Group>())
{
}
void MainMenu::input(const kku::SystemEvent& event)
{
_buttons->input(event);
}
void MainMenu::update(const kku::microsec& dt)
{
_buttons->update(dt);
}
void MainMenu::display() const
{
_buttons->display();
}
void MainMenu::enter()
{
const auto render_size = _core_factory->getRenderSize();
const float window_width = render_size.first;
const float window_height = render_size.second;
auto button_start = std::make_shared<PushButton>("Start", _core_factory, 48);
button_start->setRect(kku::Area<float>{window_width / 3.f, window_height / 7.f,
window_width / 3.f, window_height / 7.f});
button_start->setCallback(_callbacks.onAppendGameState);
auto button_editor = std::make_shared<PushButton>("Editor", _core_factory, 48);
button_editor->setRect(kku::Area<float>{window_width / 3.f, window_height / 7.f * 3,
window_width / 3.f, window_height / 7.f});
button_editor->setCallback(_callbacks.onAppendEditorState);
_buttons->addChild(button_start);
_buttons->addChild(button_editor);
_buttons->setVisibility();
}
void MainMenu::leave()
{
_buttons->setVisibility(false);
}

View File

@ -0,0 +1,140 @@
#include "bpmcalculatorwidget.h"
#include "tools/bpmcalculator.h"
#include "core/editor.h"
#include <iostream>
BPMCalculatorWidget::BPMCalculatorWidget(const std::shared_ptr<BPMCalculator>& bpm_calculator, const std::shared_ptr<kku::CoreFactory>& factory) :
Window(factory, "BPM Calculation"),
_bpm_calculator(bpm_calculator),
_slider(std::make_shared<BPMSlider>()),
_core_factory(factory),
_ticked(false)
{
_bpm_value = _core_factory->getText(kku::Font::Id::GUI);
_bpm_value->setCharacterSize(40);
_bpm_value->setColor(kku::Color{0, 0, 0, 255});
_bpm_value->setString("--");
/*_slap_buffer.loadFromFile("Tick.ogg");
_slap.setBuffer(_slap_buffer);
_slap.setVolume(30.);*/
}
void BPMCalculatorWidget::input(const kku::SystemEvent& event)
{
switch (event.type)
{
default:
break;
case kku::SystemEvent::Type::KeyPress:
{
if (std::get<kku::SystemEvent::Key>(event.data).view == ' ')
{
_bpm_calculator->click(_current_time());
}
break;
}
}
Window::input(event);
}
void BPMCalculatorWidget::update(const kku::microsec& dt)
{
Window::update(dt);
const auto beat_info = _bpm_calculator->fetchApproximatedInfo();
if (beat_info.BPM != 0)
{
_bpm_value->setString(std::to_string(static_cast<int>(beat_info.BPM)));
const kku::microsec until_beat = _bpm_calculator->fetchTimeUntilNextBeat(_current_time());
const auto time_relation = static_cast<long double>(beat_info.interval) / static_cast<long double>(until_beat);
const auto slider_path_left = _slider->getRect().width / time_relation;
if (slider_path_left < 50)
{
//if (!_ticked)
//_slap.play();
_ticked = true;
}
else
_ticked = false;
_slider->setTickPosition(slider_path_left);
}
}
void BPMCalculatorWidget::display() const
{
Window::display();
if (_is_visible)
{
_slider->display();
_button_start->display();
_button_stop->display();
_button_apply->display();
_bpm_value->display();
}
}
void BPMCalculatorWidget::setRect(const kku::Area<float>& rect)
{
Window::setRect(rect);
_slider->setRect(kku::Area<float>{0, 0, rect.width / 8 * 6, 100});
_slider->setPosition(kku::Point{_window_content->getRect().left + rect.width / 8,
_window_content->getRect().top + rect.height / 8 * 3});
_button_start->setRect(kku::Area<float>{0, 0, rect.width / 10 * 3, 30});
_button_start->setPosition(kku::Point{_window_content->getRect().left + rect.width / 7,
_window_content->getRect().top + _window_content->getRect().height - 40});
_button_stop->setRect(kku::Area<float>{0, 0, rect.width / 10 * 3, 30});
_button_stop->setPosition(kku::Point{_window_content->getRect().left + rect.width / 7,
_window_content->getRect().top + _window_content->getRect().height - 40});
_button_apply->setRect(kku::Area<float>{0, 0, rect.width / 10 * 3, 30});
_button_apply->setPosition(kku::Point{_window_content->getRect().left + 50 + (2 * (rect.width / 7)),
_window_content->getRect().top + _window_content->getRect().height - 40});
_bpm_value->setPosition(kku::Point{_window_content->getRect().left + rect.width / 8,
_window_content->getRect().top + rect.height / 8 });
}
void BPMCalculatorWidget::move(const kku::Vector2<float>& delta)
{
Window::move(delta);
_slider->move(delta);
_bpm_value->move(delta);
}
void BPMCalculatorWidget::setPosition(const kku::Point& position)
{
Window::setPosition(position);
}
void BPMCalculatorWidget::init(Init &&init)
{
_button_start = init.start;
_button_stop = init.stop;
_button_apply = init.apply;
_current_time = init.current_time;
addChild(_button_start);
addChild(_button_stop);
addChild(_button_apply);
_button_stop->setVisibility(false);
}
void BPMCalculatorWidget::setVisibility(bool is_visible)
{
Window::setVisibility(is_visible);
bool can_stop = _bpm_calculator->calculating();
_button_stop->setVisibility(can_stop && is_visible);
_button_start->setVisibility(!can_stop && is_visible);
}

View File

@ -0,0 +1,54 @@
#pragma once
#include "core/time.h"
#include "core/text.h"
#include "window.h"
#include "bpmslider.h"
#include "pushbutton.h"
#include <functional>
class BPMCalculator;
class Editor;
class BPMCalculatorWidget : public Window
{
public:
struct Init
{
std::shared_ptr<PushButton> start;
std::shared_ptr<PushButton> stop;
std::shared_ptr<PushButton> apply;
std::function<kku::microsec(void)> current_time;
};
explicit BPMCalculatorWidget(const std::shared_ptr<BPMCalculator>& bpm_calculator, const std::shared_ptr<kku::CoreFactory>& factory);
virtual void input(const kku::SystemEvent& event) override;
virtual void update(const kku::microsec& dt) override;
virtual void display() const override;
virtual void move(const kku::Vector2<float>& delta) override;
virtual void setRect(const kku::Area<float>& rect) override;
virtual void setPosition(const kku::Point& position) override;
virtual void setVisibility(bool is_visible = true) override;
void init(Init&& init);
private:
std::shared_ptr<PushButton> _button_start;
std::shared_ptr<PushButton> _button_stop;
std::shared_ptr<PushButton> _button_apply;
std::shared_ptr<BPMCalculator> _bpm_calculator;
std::shared_ptr<BPMSlider> _slider;
const std::shared_ptr<kku::CoreFactory> _core_factory;
bool _ticked;
std::shared_ptr<kku::Text> _bpm_value;
std::function<kku::microsec(void)> _current_time;
};

View File

@ -0,0 +1,66 @@
#include "bpmslider.h"
BPMSlider::BPMSlider()
{
_slider_background->setColor(kku::Color{0, 0, 0, 255});
_slider_tick->setColor(kku::Color{255, 0, 0, 255});
}
void BPMSlider::input(const kku::SystemEvent& event)
{
Widget::input(event);
}
void BPMSlider::update(const kku::microsec& dt)
{
Widget::update(dt);
}
void BPMSlider::display() const
{
_slider_background->display();
_slider_tick->display();
Widget::display();
}
void BPMSlider::setRect(const kku::Area<float>& rect)
{
_slider_background->setRect(rect);
_slider_tick->setRect(kku::Area<float>{rect.left,
rect.top,
rect.width / 30.f,
rect.height});
}
void BPMSlider::setPosition(const kku::Point& position)
{
_slider_background->setPosition(position);
_slider_tick->setPosition(position);
}
void BPMSlider::move(const kku::Vector2<float>& delta)
{
_slider_background->move(delta);
_slider_tick->move(delta);
}
bool BPMSlider::isUnderMouse(const kku::Point& position) const
{
return _slider_background->contains(position);
}
kku::Area<float> BPMSlider::getRect() const
{
return _slider_background->getRect();
}
kku::Point BPMSlider::getPosition() const
{
return _slider_background->getPosition();
}
void BPMSlider::setTickPosition(float x_position)
{
_slider_tick->setPosition(kku::Point{_slider_background->getPosition().x + x_position,
_slider_tick->getPosition().y});
}

View File

@ -0,0 +1,30 @@
#pragma once
#include "widget.h"
#include "core/rectangle.h"
class BPMSlider : public Widget
{
public:
explicit BPMSlider();
virtual void input(const kku::SystemEvent& event) override;
virtual void update(const kku::microsec& dt) override;
virtual void display() const override;
virtual void move(const kku::Vector2<float>& delta) override;
virtual bool isUnderMouse(const kku::Point& position) const override;
virtual void setRect(const kku::Area<float>& rect) override;
virtual kku::Area<float> getRect() const override;
virtual void setPosition(const kku::Point& position) override;
virtual kku::Point getPosition() const override;
void setTickPosition(float x_position);
private:
std::shared_ptr<kku::Rectangle> _slider_background;
std::shared_ptr<kku::Rectangle> _slider_tick;
};

View File

@ -0,0 +1,70 @@
#include "button.h"
#include <iostream>
Button::Button(const std::string &text, const std::shared_ptr<kku::CoreFactory>& factory, unsigned int font_size) :
_core_factory(factory)
{
_button_text = _core_factory->getText(kku::Font::Id::GUI);
_button_text->setString(text);
_button_text->setColor(kku::Color{0, 0, 0, 255});
_button_text->setCharacterSize(font_size);
}
void Button::update(const kku::microsec& dt)
{
Widget::update(dt);
}
void Button::display() const
{
if (_is_visible)
{
_button_content->display();
_button_text->display();
}
Widget::display();
}
void Button::setRect(const kku::Area<float>& rect)
{
_button_content->setRect(rect);
_button_text->setPosition(kku::Point{rect.left + 5,
rect.top + 5});
}
void Button::setPosition(const kku::Point& position)
{
_button_content->setPosition(position);
auto new_point = position;
new_point.moveBy(5.f, 5.f);
_button_text->setPosition(new_point);
}
void Button::move(const kku::Vector2<float>& delta)
{
_button_content->move(delta);
_button_text->move(delta);
Widget::move(delta);
}
bool Button::isUnderMouse(const kku::Point& position) const
{
return _is_visible && _button_content->contains(position);
}
void Button::setText(const std::string& text)
{
_button_text->setString(text);
}
kku::Area<float> Button::getRect() const
{
return _button_content->getRect();
}
kku::Point Button::getPosition() const
{
return _button_content->getPosition();
}

View File

@ -0,0 +1,33 @@
#pragma once
#include "widget.h"
#include "core/corefactory.h"
#include <functional>
class Button : public Widget
{
public:
explicit Button(const std::string& text, const std::shared_ptr<kku::CoreFactory>& factory, unsigned int font_size);
virtual void input(const kku::SystemEvent& event) override = 0;
virtual void update(const kku::microsec& dt) override final;
virtual void display() const override final;
virtual void move(const kku::Vector2<float>& delta) override final;
virtual bool isUnderMouse(const kku::Point& position) const override final;
virtual void setRect(const kku::Area<float>& rect) override;
virtual kku::Area<float> getRect() const override;
virtual void setPosition(const kku::Point& position) override;
virtual kku::Point getPosition() const override;
virtual void setText(const std::string& text);
protected:
std::shared_ptr<kku::Rectangle> _button_content;
std::shared_ptr<kku::Text> _button_text;
const std::shared_ptr<kku::CoreFactory> _core_factory;
};

View File

@ -0,0 +1,75 @@
#include "cascademenubutton.h"
#include "menudrop.h"
CascadeMenuButton::CascadeMenuButton(const std::string& text, const std::shared_ptr<kku::CoreFactory>& factory, unsigned int font_size) :
Button(text, factory, font_size)
{
_color_idle = kku::Color{230, 230, 230, 255};
_color_hover = kku::Color{84, 158, 253, 255};
_button_content->setColor(_color_idle);
}
void CascadeMenuButton::input(const kku::SystemEvent& event)
{
if (!_submenu)
return;
switch (event.type)
{
default:
break;
case kku::SystemEvent::Type::MouseMove:
{
const auto position = std::get<kku::SystemEvent::Mouse>(event.data).position;
if (isUnderMouse(position))
{
_button_content->setColor(_color_hover);
_submenu->lock();
_submenu->setVisibility(true);
}
else
{
_submenu->unlock();
if (!_submenu->isVisible())
{
_button_content->setColor(_color_idle);
}
}
break;
}
}
}
void CascadeMenuButton::setRect(const kku::Area<float>& rect)
{
Button::setRect(rect);
resetRect();
}
void CascadeMenuButton::setSubmenu(const std::shared_ptr<MenuDrop>& submenu)
{
_submenu = submenu;
resetRect();
}
const std::shared_ptr<MenuDrop> CascadeMenuButton::submenu() const
{
return _submenu;
}
void CascadeMenuButton::resetRect()
{
if (_submenu)
{
_submenu->setPosition(kku::Point{_button_content->getPosition().x + _button_content->getRect().width,
_button_content->getPosition().y});
}
}
void CascadeMenuButton::setFillColors(kku::Color&& idle_color, kku::Color&& hover_color)
{
_color_idle = idle_color;
_color_hover = hover_color;
}

View File

@ -7,19 +7,19 @@ class MenuDrop;
class CascadeMenuButton : public Button
{
public:
explicit CascadeMenuButton(const std::string& text, const std::shared_ptr<sf::Font>& font, unsigned int font_size = 12);
virtual void input(const sf::Event& event) override final;
virtual void setRect(const sf::FloatRect& rect) override final;
explicit CascadeMenuButton(const std::string& text, const std::shared_ptr<kku::CoreFactory>& factory, unsigned int font_size = 12);
virtual void input(const kku::SystemEvent& event) override final;
virtual void setRect(const kku::Area<float>& rect) override final;
void setSubmenu(const std::shared_ptr<MenuDrop>& submenu);
const std::shared_ptr<MenuDrop> submenu() const;
void resetRect();
void setFillColors(sf::Color&& idle_color, sf::Color&& hover_color);
void setFillColors(kku::Color&& idle_color, kku::Color&& hover_color);
private:
std::shared_ptr<MenuDrop> _submenu;
sf::Color _color_idle;
sf::Color _color_hover;
kku::Color _color_idle;
kku::Color _color_hover;
};

View File

@ -0,0 +1,55 @@
#include "editorwidget.h"
#include "core/editor.h"
EditorWidget::EditorWidget(Callbacks&& callbacks) :
_input(std::move(callbacks.onInput)),
_update(std::move(callbacks.onUpdate)),
_draw(std::move(callbacks.onDisplay))
{}
void EditorWidget::input(const kku::SystemEvent& event)
{
_input(event);
}
void EditorWidget::update(const kku::microsec& dt)
{
_update(dt);
}
void EditorWidget::display() const
{
_draw();
}
void EditorWidget::move(const kku::Vector2<float>& delta)
{
(void)delta;
// delegate to children
}
bool EditorWidget::isUnderMouse(const kku::Point& position) const
{
return _parent->isUnderMouse(position);
}
void EditorWidget::setRect(const kku::Area<float>& rect)
{
(void)rect;
// basically useless beacuse editor widget fills the entire screen
}
kku::Area<float> EditorWidget::getRect() const
{
return {};
}
void EditorWidget::setPosition(const kku::Point& position)
{
(void)position;
}
kku::Point EditorWidget::getPosition() const
{
return kku::Point{};
}

View File

@ -0,0 +1,36 @@
#pragma once
#include "widget.h"
#include <functional>
class EditorWidget : public Widget
{
public:
struct Callbacks
{
std::function<void(const kku::SystemEvent& event)> onInput;
std::function<void(const kku::microsec& dt)> onUpdate;
std::function<void(void)> onDisplay;
};
explicit EditorWidget(Callbacks&& callbacks);
virtual void input(const kku::SystemEvent& event) override;
virtual void update(const kku::microsec& dt) override;
virtual void display() const override;
virtual void move(const kku::Vector2<float>& delta) override;
virtual bool isUnderMouse(const kku::Point& position) const override;
virtual void setRect(const kku::Area<float>& rect) override;
virtual kku::Area<float> getRect() const override;
virtual void setPosition(const kku::Point& position) override;
virtual kku::Point getPosition() const override;
private:
std::function<void(const kku::SystemEvent& event)> _input;
std::function<void(const kku::microsec& dt)> _update;
std::function<void(void)> _draw;
};

View File

@ -0,0 +1,55 @@
#include "group.h"
void Group::input(const kku::SystemEvent& event)
{
Widget::input(event);
}
void Group::update(const kku::microsec& dt)
{
Widget::update(dt);
}
void Group::display() const
{
Widget::display();
}
void Group::setRect(const kku::Area<float>& rect)
{
_rect = rect;
}
void Group::setPosition(const kku::Point& position)
{
_rect.top = position.y;
_rect.left = position.x;
}
void Group::move(const kku::Vector2<float>& delta)
{
_rect.top += delta.first;
_rect.left += delta.second;
Widget::move(delta);
}
bool Group::isUnderMouse(const kku::Point& position) const
{
return _rect.contains(position);
}
kku::Area<float> Group::getRect() const
{
return _rect;
}
kku::Point Group::getPosition() const
{
return kku::Point
{
_rect.top,
_rect.left
};
}

View File

@ -0,0 +1,23 @@
#pragma once
#include "widget.h"
class Group : public Widget
{
public:
virtual void input(const kku::SystemEvent& event) override;
virtual void update(const kku::microsec& dt) override;
virtual void display() const override;
virtual void move(const kku::Vector2<float>& delta) override;
virtual bool isUnderMouse(const kku::Point& position) const override;
virtual void setRect(const kku::Area<float>& rect) override;
virtual kku::Area<float> getRect() const override;
virtual void setPosition(const kku::Point& position) override;
virtual kku::Point getPosition() const override;
private:
kku::Area<float> _rect;
};

View File

@ -0,0 +1,131 @@
#include "menubar.h"
MenuBar::MenuBar(const std::shared_ptr<kku::CoreFactory>& factory) :
_core_factory(factory),
_bar_rect(factory->getRectangle()),
_amount_buttons(0),
_button_width(170)
{
_bar_rect->setColor(kku::Color{88, 57, 107, 255});
}
void MenuBar::input(const kku::SystemEvent &event)
{
switch (event.type)
{
default:
break;
case kku::SystemEvent::Type::MouseRelease:
{
const auto position = std::get<kku::SystemEvent::Mouse>(event.data).position;
if (!isUnderMouse(position))
{
for (auto& submenu : _submenus)
submenu->unlock();
}
break;
}
}
Widget::input(event);
}
void MenuBar::update(const kku::microsec& dt)
{
Widget::update(dt);
}
void MenuBar::display() const
{
if (_is_visible)
_bar_rect->display();
Widget::display();
}
void MenuBar::setRect(const kku::Area<float>& rect)
{
_bar_rect->setRect(rect);
// Buttons will not resize
}
void MenuBar::setPosition(const kku::Point& position)
{
_bar_rect->setPosition(position);
}
void MenuBar::move(const kku::Vector2<float>& delta)
{
_bar_rect->move(delta);
Widget::move(delta);
for (auto& menu : _submenus)
menu->move(delta);
}
bool MenuBar::isUnderMouse(const kku::Point& position) const
{
bool bar_under_mouse = _bar_rect->contains(position);
bool submenus_under_mouse = std::any_of(_children.begin(), _children.end(),
[p=position](const auto& child)
{
return child->isUnderMouse(p);
});
return bar_under_mouse || submenus_under_mouse;
}
void MenuBar::addRootSubMenu(std::string name, const std::shared_ptr<MenuDrop>& submenu)
{
const auto new_button = std::make_shared<PushButton>(name, _core_factory);
std::size_t current_index = _amount_buttons;
new_button->setRect(kku::Area<float>{static_cast<float>(current_index * _button_width),
0.f,
static_cast<float>(_button_width),
_bar_rect->getRect().height});
new_button->setCallback([submenu=submenu]()
{
submenu->setVisibility(true);
submenu->lock();
});
submenu->setPosition(kku::Point{static_cast<float>(current_index * _button_width),
_bar_rect->getRect().height});
new_button->setColors(kku::Color{171, 141, 189, 255},
kku::Color{48, 27, 57, 255});
addChild(new_button);
addChild(submenu);
_submenus.emplace_back(submenu);
++_amount_buttons;
}
void MenuBar::addDependentSubmenu(const std::shared_ptr<MenuDrop> &submenu)
{
_submenus.emplace_back(submenu);
}
void MenuBar::setVisibility(bool is_visible)
{
Widget::setVisibility(is_visible);
for (auto& submenu : _submenus)
submenu->setVisibility(false);
}
kku::Area<float> MenuBar::getRect() const
{
return _bar_rect->getRect();
}
kku::Point MenuBar::getPosition() const
{
return _bar_rect->getPosition();
}

View File

@ -0,0 +1,35 @@
#pragma once
#include "widget.h"
#include "menudrop.h"
#include "button.h"
class MenuBar : public Widget
{
public:
explicit MenuBar(const std::shared_ptr<kku::CoreFactory>& factory);
virtual void input(const kku::SystemEvent& event) override;
virtual void update(const kku::microsec& dt) override;
virtual void display() const override;
virtual void move(const kku::Vector2<float>& delta) override;
virtual bool isUnderMouse(const kku::Point& position) const override;
virtual void setVisibility(bool is_visible = true) override;
virtual void setRect(const kku::Area<float>& rect) override;
virtual kku::Area<float> getRect() const override;
virtual void setPosition(const kku::Point& position) override;
virtual kku::Point getPosition() const override;
void addRootSubMenu(std::string name, const std::shared_ptr<MenuDrop>& submenu);
void addDependentSubmenu(const std::shared_ptr<MenuDrop>& submenu);
private:
const std::shared_ptr<kku::CoreFactory> _core_factory;
const std::shared_ptr<kku::Rectangle> _bar_rect;
std::size_t _amount_buttons;
std::size_t _button_width;
std::vector<std::shared_ptr<MenuDrop>> _submenus;
};

View File

@ -1,16 +1,17 @@
#include "menudrop.h"
#include "menuseparator.h"
#include "core/corefactory.h"
MenuDrop::MenuDrop() :
MenuDrop::MenuDrop(const std::shared_ptr<kku::CoreFactory>& factory) :
_is_locked(false),
_button_height(27),
_button_index(0)
{
_is_visible = false;
_content_rect.setFillColor(sf::Color(200, 200, 200));
_content_rect = factory->getRectangle();
_content_rect->setColor(kku::Color{200, 200, 200, 255});
}
void MenuDrop::input(const sf::Event& event)
void MenuDrop::input(const kku::SystemEvent& event)
{
if (!_is_visible)
return;
@ -22,8 +23,10 @@ void MenuDrop::input(const sf::Event& event)
default:
break;
case sf::Event::MouseButtonReleased:
if (isUnderMouse(event.mouseButton.x, event.mouseButton.y))
case kku::SystemEvent::Type::MouseRelease:
{
const auto position = std::get<kku::SystemEvent::Mouse>(event.data).position;
if (isUnderMouse(position))
{
setVisibility(false);
for (auto& submenu : _submenus)
@ -33,14 +36,19 @@ void MenuDrop::input(const sf::Event& event)
}
}
break;
case sf::Event::MouseMoved:
if (!isUnderMouse(event.mouseMove.x, event.mouseMove.y))
}
case kku::SystemEvent::Type::MouseMove:
{
const auto position = std::get<kku::SystemEvent::Mouse>(event.data).position;
if (!isUnderMouse(position))
{
if (!isLocked() && !hasActiveSubmenus())
setVisibility(false);
}
break;
}
}
}
bool MenuDrop::hasActiveSubmenus() const
@ -52,33 +60,32 @@ bool MenuDrop::hasActiveSubmenus() const
});
}
void MenuDrop::update(const sf::Time& dt)
void MenuDrop::update(const kku::microsec& dt)
{
Widget::update(dt);
}
void MenuDrop::draw(sf::RenderTarget& target, sf::RenderStates states) const
void MenuDrop::display() const
{
if (_is_visible)
target.draw(_content_rect);
_content_rect->display();
Widget::draw(target, states);
Widget::display();
}
void MenuDrop::setRect(const sf::FloatRect& rect)
void MenuDrop::setRect(const kku::Area<float>& rect)
{
_content_rect.setPosition(rect.left, rect.top);
_content_rect.setSize({rect.width, rect.height});
_content_rect->setRect(rect);
}
void MenuDrop::setPosition(const sf::Vector2f& position)
void MenuDrop::setPosition(const kku::Point& position)
{
_content_rect.setPosition(position);
_content_rect->setPosition(position);
}
void MenuDrop::move(const sf::Vector2f& delta)
void MenuDrop::move(const kku::Vector2<float>& delta)
{
_content_rect.move(delta);
_content_rect->move(delta);
Widget::move(delta);
@ -86,9 +93,9 @@ void MenuDrop::move(const sf::Vector2f& delta)
submenu->move(delta);
}
bool MenuDrop::isUnderMouse(int mouse_x, int mouse_y) const
bool MenuDrop::isUnderMouse(const kku::Point& position) const
{
return _is_visible && _content_rect.getGlobalBounds().contains(mouse_x, mouse_y);
return _is_visible && _content_rect->contains(position);
}
void MenuDrop::setVisibility(bool is_visible)
@ -113,20 +120,19 @@ void MenuDrop::addCascadeButton(const std::shared_ptr<CascadeMenuButton>& button
submenu->setParent(_parent);
}
void MenuDrop::addSeparator()
void MenuDrop::addSeparator(const std::shared_ptr<MenuSeparator>& separator)
{
add(std::make_shared<MenuSeparator>());
add(separator);
}
void MenuDrop::add(const std::shared_ptr<Widget> &widget)
{
const auto& parent_size = _content_rect.getSize();
const auto& parent_position = _content_rect.getPosition();
const auto& parent_rect = _content_rect->getRect();
widget->setRect(sf::FloatRect(parent_position.x,
parent_position.y + (_button_height * _button_index),
parent_size.x,
_button_height));
widget->setRect(kku::Area<float>{parent_rect.left,
parent_rect.top + (parent_rect.height * _button_index),
parent_rect.width,
static_cast<float>(_button_height)});
addChild(widget);
++_button_index;
@ -147,12 +153,12 @@ bool MenuDrop::isLocked() const
return _is_locked;
}
sf::FloatRect MenuDrop::rect() const
kku::Area<float> MenuDrop::getRect() const
{
return _content_rect.getGlobalBounds();
return _content_rect->getRect();
}
sf::Vector2f MenuDrop::position() const
kku::Point MenuDrop::getPosition() const
{
return _content_rect.getPosition();
return _content_rect->getPosition();
}

View File

@ -0,0 +1,46 @@
#pragma once
#include "widget.h"
#include "pushbutton.h"
#include "cascademenubutton.h"
#include "menuseparator.h"
#include "core/rectangle.h"
class MenuDrop : public Widget
{
public:
explicit MenuDrop(const std::shared_ptr<kku::CoreFactory>& factory);
virtual void input(const kku::SystemEvent& event) override;
virtual void update(const kku::microsec& dt) override;
virtual void display() const override;
virtual void move(const kku::Vector2<float>& delta) override;
virtual bool isUnderMouse(const kku::Point& position) const override;
virtual void setVisibility(bool is_visible = true) override;
virtual void setRect(const kku::Area<float>& rect) override;
virtual kku::Area<float> getRect() const override;
virtual void setPosition(const kku::Point& position) override;
virtual kku::Point getPosition() const override;
void addPushButton(const std::shared_ptr<PushButton>& button);
void addCascadeButton(const std::shared_ptr<CascadeMenuButton>& button);
void addSeparator(const std::shared_ptr<MenuSeparator>& separator);
void lock();
void unlock();
bool isLocked() const;
private:
std::shared_ptr<kku::Rectangle> _content_rect;
bool _is_locked;
std::size_t _button_height;
std::size_t _button_index;
std::vector<std::shared_ptr<MenuDrop>> _submenus;
void add(const std::shared_ptr<Widget>& widget);
bool hasActiveSubmenus() const;
};

View File

@ -0,0 +1,48 @@
#include "menuseparator.h"
void MenuSeparator::input(const kku::SystemEvent& event)
{
Widget::input(event);
}
void MenuSeparator::update(const kku::microsec& dt)
{
Widget::update(dt);
}
void MenuSeparator::display() const
{
_line->display();
}
void MenuSeparator::setRect(const kku::Area<float>& rect)
{
_rect = rect;
//_line
}
void MenuSeparator::setPosition(const kku::Point& position)
{
(void)position;
}
void MenuSeparator::move(const kku::Vector2<float>& delta)
{
(void)delta;
}
bool MenuSeparator::isUnderMouse(const kku::Point& position) const
{
return _is_visible && _rect.contains(position);
}
kku::Area<float> MenuSeparator::getRect() const
{
return {};
}
kku::Point MenuSeparator::getPosition() const
{
return kku::Point{};
}

View File

@ -0,0 +1,25 @@
#pragma once
#include "widget.h"
#include "core/line.h"
class MenuSeparator : public Widget
{
public:
virtual void input(const kku::SystemEvent& event) override;
virtual void update(const kku::microsec& dt) override;
virtual void display() const override;
virtual void move(const kku::Vector2<float>& delta) override;
virtual bool isUnderMouse(const kku::Point& position) const override;
virtual void setRect(const kku::Area<float>& rect) override;
virtual kku::Area<float> getRect() const override;
virtual void setPosition(const kku::Point& position) override;
virtual kku::Point getPosition() const override;
private:
std::shared_ptr<kku::Line> _line;
kku::Area<float> _rect;
};

View File

@ -0,0 +1,57 @@
#include "pushbutton.h"
PushButton::PushButton(const std::string& text, const std::shared_ptr<kku::CoreFactory>& factory, unsigned int font_size) :
Button(text, factory, font_size),
_pressed(false)
{
_color_idle = kku::Color{230, 230, 230, 255};
_color_pressed = kku::Color{200, 200, 200, 255};
_button_content = _core_factory->getRectangle();
_button_content->setColor(_color_idle);
}
void PushButton::input(const kku::SystemEvent& event)
{
switch (event.type)
{
default:
break;
case kku::SystemEvent::Type::MousePress:
{
const auto position = std::get<kku::SystemEvent::Mouse>(event.data).position;
if (isUnderMouse(position))
{
_pressed = true;
_button_content->setColor(_color_pressed);
}
break;
}
case kku::SystemEvent::Type::MouseRelease:
{
if (_pressed)
{
const auto position = std::get<kku::SystemEvent::Mouse>(event.data).position;
_button_content->setColor(_color_idle);
_pressed = false;
if (isUnderMouse(position))
_on_click_callback();
}
break;
}
}
}
void PushButton::setCallback(std::function<void(void)> callback)
{
_on_click_callback = callback;
}
void PushButton::setColors(kku::Color&& idle_color, kku::Color&& pressed_color)
{
_color_idle = idle_color;
_color_pressed = pressed_color;
_button_content->setColor(_pressed ? pressed_color : idle_color);
}

View File

@ -5,15 +5,15 @@
class PushButton : public Button
{
public:
explicit PushButton(const std::string& text, const std::shared_ptr<sf::Font>& font, unsigned int font_size = 12);
virtual void input(const sf::Event& event) override final;
explicit PushButton(const std::string& text, const std::shared_ptr<kku::CoreFactory>& factory, unsigned int font_size = 12);
virtual void input(const kku::SystemEvent& event) override final;
void setCallback(std::function<void(void)> callback);
void setFillColors(sf::Color&& idle_color, sf::Color&& pressed_color);
void setColors(kku::Color&& idle_color, kku::Color&& pressed_color);
private:
sf::Color _color_idle;
sf::Color _color_pressed;
kku::Color _color_idle;
kku::Color _color_pressed;
bool _pressed;
std::function<void(void)> _on_click_callback;

View File

@ -1,6 +1,7 @@
#include "widget.h"
#include <algorithm>
void Widget::input(const sf::Event &event)
void Widget::input(const kku::SystemEvent &event)
{
if (_blocker)
_blocker->input(event);
@ -11,19 +12,19 @@ void Widget::input(const sf::Event &event)
}
}
void Widget::update(const sf::Time& dt)
void Widget::update(const kku::microsec& dt)
{
for (auto& child : _children)
child->update(dt);
}
void Widget::draw(sf::RenderTarget& target, sf::RenderStates states) const
void Widget::display() const
{
for (auto& child : _children)
child->draw(target, states);
for (const auto& child : _children)
child->display();
}
void Widget::move(const sf::Vector2f &delta)
void Widget::move(const kku::Vector2<float>& delta)
{
for (auto& child : _children)
child->move(delta);

View File

@ -0,0 +1,42 @@
#pragma once
#include <vector>
#include <memory>
#include "core/systemevent.h"
#include "core/rectangle.h"
#include "core/time.h"
class Widget : public std::enable_shared_from_this<Widget>
{
public:
virtual ~Widget() = default;
virtual void input(const kku::SystemEvent& event) = 0;
virtual void update(const kku::microsec& dt) = 0;
virtual void display() const = 0;
virtual void move(const kku::Vector2<float>& delta) = 0;
virtual bool isUnderMouse(const kku::Point& position) const = 0;
virtual void setRect(const kku::Area<float>& rect) = 0;
virtual kku::Area<float> getRect() const = 0;
virtual void setPosition(const kku::Point& position) = 0;
virtual kku::Point getPosition() const = 0;
virtual void setVisibility(bool is_visible = true);
bool isVisible() const;
void addChild(const std::shared_ptr<Widget>& child);
void setParent(const std::shared_ptr<Widget>& parent);
void blockBy(const std::shared_ptr<Widget>& blocker);
void unblock();
protected:
std::vector<std::shared_ptr<Widget>> _children;
std::shared_ptr<Widget> _parent;
std::shared_ptr<Widget> _blocker;
bool _is_visible = true;
};

View File

@ -0,0 +1,132 @@
#include "window.h"
#include "pushbutton.h"
Window::Window(const std::shared_ptr<kku::CoreFactory>& factory, const std::string& title) :
_core_factory(factory),
_is_dragging(false)
{
_bar_title = _core_factory->getText(kku::Font::Id::GUI);
_bar_title->setString(title);
_bar_title->setCharacterSize(12);
_bar_title->setColor(kku::Color{188, 157, 207, 255});
_bar = _core_factory->getRectangle();
_bar->setColor(kku::Color{88, 57, 107, 255});
_window_content = _core_factory->getRectangle();
_window_content->setColor(kku::Color{188, 157, 207, 255});
}
void Window::input(const kku::SystemEvent& event)
{
Widget::input(event);
switch (event.type)
{
default:
break;
case kku::SystemEvent::Type::MousePress:
{
const auto position = std::get<kku::SystemEvent::Mouse>(event.data).position;
if (_bar->contains(position))
{
_is_dragging = true;
_previous_click_position = position;
}
break;
}
case kku::SystemEvent::Type::MouseRelease:
_is_dragging = false;
break;
case kku::SystemEvent::Type::MouseMove:
{
const auto position = std::get<kku::SystemEvent::Mouse>(event.data).position;
if (_is_dragging)
{
float x_mouse_diff = position.x - _previous_click_position.x;
float y_mouse_diff = position.y - _previous_click_position.y;
_previous_click_position = position;
move(kku::Vector2<float>{x_mouse_diff, y_mouse_diff});
}
break;
}
}
}
void Window::update(const kku::microsec& dt)
{
Widget::update(dt);
}
void Window::display() const
{
if (_is_visible)
{
_window_content->display();
_bar->display();
_bar_title->display();
Widget::display();
}
}
void Window::setRect(const kku::Area<float>& rect)
{
_window_content->setRect(rect);
kku::Area<float> bar_rect = {rect.left, rect.top, rect.width, 30};
_bar->setRect(bar_rect);
_bar_title->setPosition(kku::Point{rect.left + 5,
rect.top + 5});
}
void Window::setPosition(const kku::Point& position)
{
_window_content->setPosition(position);
_bar->setPosition(position);
auto new_position = position;
new_position.moveBy(5.f, 5.f);
_bar_title->setPosition(new_position);
}
void Window::move(const kku::Vector2<float>& delta)
{
_window_content->move(delta);
_bar->move(delta);
_bar_title->move(delta);
Widget::move(delta);
}
bool Window::isUnderMouse(const kku::Point& position) const
{
return _is_visible && _window_content->contains(position);
}
void Window::addBarButton(const std::string &text, std::function<void(void)> callback)
{
const auto area = _window_content->getRect();
auto b = std::make_shared<PushButton>(text, _core_factory, 20);
b->setCallback(callback);
b->setRect({area.left + area.width - 35,
area.top, 30, 30});
Widget::addChild(b);
}
kku::Area<float> Window::getRect() const
{
return _window_content->getRect();
}
kku::Point Window::getPosition() const
{
return _window_content->getPosition();
}

View File

@ -0,0 +1,41 @@
#pragma once
#include "widget.h"
#include "core/corefactory.h"
#include "core/rectangle.h"
#include "core/vector.h"
#include "core/text.h"
#include <functional>
class Window : public Widget
{
public:
explicit Window(const std::shared_ptr<kku::CoreFactory>& factory, const std::string& title);
virtual void input(const kku::SystemEvent& event) override;
virtual void update(const kku::microsec& dt) override;
virtual void display() const override;
virtual void move(const kku::Vector2<float>& delta) override;
virtual bool isUnderMouse(const kku::Point& position) const override final;
virtual void setRect(const kku::Area<float>& rect) override;
virtual kku::Area<float> getRect() const override;
virtual void setPosition(const kku::Point& position) override;
virtual kku::Point getPosition() const override;
void addBarButton(const std::string& text, std::function<void(void)> callback);
protected:
std::shared_ptr<kku::Rectangle> _bar;
std::shared_ptr<kku::Rectangle> _window_content;
std::shared_ptr<kku::Text> _bar_title;
const std::shared_ptr<kku::CoreFactory> _core_factory;
private:
bool _is_dragging;
kku::Point _previous_click_position;
};

View File

@ -1,136 +0,0 @@
#include "bpmcalculatorwidget.h"
#include "tools/bpmcalculator.h"
#include "core/editor.h"
#include <iostream>
BPMCalculatorWidget::BPMCalculatorWidget(const std::shared_ptr<BPMCalculator>& bpm_calculator, const std::shared_ptr<sf::Font>& font) :
Window("BPM Calculation", font),
_bpm_calculator(bpm_calculator),
_slider(std::make_shared<BPMSlider>()),
_ticked(false)
{
_bpm_value.setFont(*_font);
_bpm_value.setCharacterSize(40);
_bpm_value.setFillColor(sf::Color::Black);
_bpm_value.setString("--");
_slap_buffer.loadFromFile("Tick.ogg");
_slap.setBuffer(_slap_buffer);
_slap.setVolume(30.);
}
void BPMCalculatorWidget::input(const sf::Event& event)
{
switch (event.type)
{
default:
break;
case sf::Event::KeyPressed:
if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Space)
{
_bpm_calculator->click(_current_time());
}
break;
}
Window::input(event);
}
void BPMCalculatorWidget::update(const sf::Time& dt)
{
Window::update(dt);
const auto beat_info = _bpm_calculator->fetchApproximatedInfo();
if (beat_info.BPM != 0)
{
_bpm_value.setString(std::to_string(static_cast<int>(beat_info.BPM)));
const microsec until_beat = _bpm_calculator->fetchTimeUntilNextBeat(_current_time());
const auto time_relation = static_cast<long double>(beat_info.interval) / static_cast<long double>(until_beat);
const auto slider_path_left = _slider->rect().width / time_relation;
if (slider_path_left < 50)
{
if (!_ticked)
_slap.play();
_ticked = true;
}
else
_ticked = false;
_slider->setTickPosition(slider_path_left);
}
}
void BPMCalculatorWidget::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
Window::draw(target, states);
if (_is_visible)
{
_slider->draw(target, states);
_button_start->draw(target, states);
_button_stop->draw(target, states);
_button_apply->draw(target, states);
target.draw(_bpm_value, states);
}
}
void BPMCalculatorWidget::setRect(const sf::FloatRect& rect)
{
Window::setRect(rect);
_slider->setRect(sf::FloatRect{0, 0, rect.width / 8 * 6, 100});
_slider->setPosition({_window_content.getGlobalBounds().left + rect.width / 8,
_window_content.getGlobalBounds().top + rect.height / 8 * 3});
_button_start->setRect(sf::FloatRect{0, 0, rect.width / 10 * 3, 30});
_button_start->setPosition({_window_content.getGlobalBounds().left + rect.width / 7,
_window_content.getGlobalBounds().top + _window_content.getGlobalBounds().height - 40});
_button_stop->setRect(sf::FloatRect{0, 0, rect.width / 10 * 3, 30});
_button_stop->setPosition({_window_content.getGlobalBounds().left + rect.width / 7,
_window_content.getGlobalBounds().top + _window_content.getGlobalBounds().height - 40});
_button_apply->setRect(sf::FloatRect{0, 0, rect.width / 10 * 3, 30});
_button_apply->setPosition({_window_content.getGlobalBounds().left + 50 + (2 * (rect.width / 7)),
_window_content.getGlobalBounds().top + _window_content.getGlobalBounds().height - 40});
_bpm_value.setPosition({_window_content.getGlobalBounds().left + rect.width / 8,
_window_content.getGlobalBounds().top + rect.height / 8 });
}
void BPMCalculatorWidget::move(const sf::Vector2f &delta)
{
Window::move(delta);
_slider->move(delta);
_bpm_value.move(delta);
}
void BPMCalculatorWidget::setPosition(const sf::Vector2f &position)
{
Window::setPosition(position);
}
void BPMCalculatorWidget::init(Init &&init)
{
_button_start = init.start;
_button_stop = init.stop;
_button_apply = init.apply;
_current_time = init.current_time;
addChild(_button_start);
addChild(_button_stop);
addChild(_button_apply);
_button_stop->setVisibility(false);
}
void BPMCalculatorWidget::setVisibility(bool is_visible)
{
Window::setVisibility(is_visible);
bool can_stop = _bpm_calculator->calculating();
_button_stop->setVisibility(can_stop && is_visible);
_button_start->setVisibility(!can_stop && is_visible);
}

View File

@ -1,56 +0,0 @@
#pragma once
#include "window.h"
#include "bpmslider.h"
#include "pushbutton.h"
#include <functional>
#include <SFML/Graphics/RectangleShape.hpp>
#include <SFML/Graphics/Text.hpp>
#include <SFML/Audio/Sound.hpp>
#include <SFML/Audio/SoundBuffer.hpp>
#include "tools/mathutils.h"
class BPMCalculator;
class Editor;
class BPMCalculatorWidget : public Window
{
public:
struct Init
{
std::shared_ptr<PushButton> start;
std::shared_ptr<PushButton> stop;
std::shared_ptr<PushButton> apply;
std::function<microsec(void)> current_time;
};
explicit BPMCalculatorWidget(const std::shared_ptr<BPMCalculator>& bpm_calculator, const std::shared_ptr<sf::Font> &font);
virtual void input(const sf::Event& event) override;
virtual void update(const sf::Time& dt) override;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
virtual void setRect(const sf::FloatRect& rect) override;
virtual void setPosition(const sf::Vector2f& position) override;
virtual void move(const sf::Vector2f& delta) override;
virtual void setVisibility(bool is_visible = true) override;
void init(Init&& init);
private:
std::shared_ptr<PushButton> _button_start;
std::shared_ptr<PushButton> _button_stop;
std::shared_ptr<PushButton> _button_apply;
std::shared_ptr<BPMCalculator> _bpm_calculator;
std::shared_ptr<BPMSlider> _slider;
sf::SoundBuffer _slap_buffer;
sf::Sound _slap;
bool _ticked;
sf::Text _bpm_value;
std::function<microsec(void)> _current_time;
};

View File

@ -1,65 +0,0 @@
#include "bpmslider.h"
BPMSlider::BPMSlider()
{
_slider_background.setFillColor(sf::Color::Black);
_slider_tick.setFillColor(sf::Color::Red);
}
void BPMSlider::input(const sf::Event& event)
{
Widget::input(event);
}
void BPMSlider::update(const sf::Time& dt)
{
Widget::update(dt);
}
void BPMSlider::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
target.draw(_slider_background, states);
target.draw(_slider_tick, states);
Widget::draw(target, states);
}
void BPMSlider::setRect(const sf::FloatRect& rect)
{
_slider_background.setPosition(rect.left, rect.top);
_slider_background.setSize({rect.width, rect.height});
_slider_tick.setPosition(rect.left, rect.top);
_slider_tick.setSize({rect.width / 30, rect.height});
}
void BPMSlider::setPosition(const sf::Vector2f& position)
{
_slider_background.setPosition(position);
_slider_tick.setPosition(position);
}
void BPMSlider::move(const sf::Vector2f& delta)
{
_slider_background.move(delta);
_slider_tick.move(delta);
}
bool BPMSlider::isUnderMouse(int mouse_x, int mouse_y) const
{
return mouse_x == mouse_y; // just to compile
}
sf::FloatRect BPMSlider::rect() const
{
return _slider_background.getGlobalBounds();
}
sf::Vector2f BPMSlider::position() const
{
return _slider_background.getPosition();
}
void BPMSlider::setTickPosition(float x_position)
{
_slider_tick.setPosition(_slider_background.getPosition().x + x_position, _slider_tick.getPosition().y);
}

View File

@ -1,32 +0,0 @@
#pragma once
#include "widget.h"
#include <SFML/Graphics/RectangleShape.hpp>
#include <SFML/Graphics/Text.hpp>
class BPMSlider : public Widget
{
public:
explicit BPMSlider();
virtual void input(const sf::Event& event) override;
virtual void update(const sf::Time& dt) override;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
virtual void move(const sf::Vector2f& delta) override;
virtual bool isUnderMouse(int mouse_x, int mouse_y) const override;
virtual void setRect(const sf::FloatRect& rect) override;
virtual sf::FloatRect rect() const override;
virtual void setPosition(const sf::Vector2f& position) override;
virtual sf::Vector2f position() const override;
void setTickPosition(float x_position);
private:
sf::RectangleShape _slider_background;
sf::RectangleShape _slider_tick;
};

View File

@ -1,67 +0,0 @@
#include "button.h"
#include <iostream>
Button::Button(const std::string &text, const std::shared_ptr<sf::Font>& font, unsigned int font_size) :
_font(font)
{
setText(text);
_button_text.setFillColor(sf::Color::Black);
_button_text.setCharacterSize(font_size);
_button_text.setFont(*_font);
}
void Button::update(const sf::Time& dt)
{
Widget::update(dt);
}
void Button::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
if (_is_visible)
{
target.draw(_button_content, states);
target.draw(_button_text, states);
}
Widget::draw(target, states);
}
void Button::setRect(const sf::FloatRect& rect)
{
_button_content.setPosition(rect.left, rect.top);
_button_content.setSize({rect.width, rect.height});
_button_text.setPosition(rect.left + 5, rect.top + 5);
}
void Button::setPosition(const sf::Vector2f &position)
{
_button_content.setPosition(position);
_button_text.move(position.x + 5, position.y + 5);
}
void Button::move(const sf::Vector2f &delta)
{
_button_content.move(delta);
_button_text.move(delta);
Widget::move(delta);
}
bool Button::isUnderMouse(int mouse_x, int mouse_y) const
{
return _is_visible && _button_content.getGlobalBounds().contains(mouse_x, mouse_y);
}
void Button::setText(const std::string& text)
{
_button_text.setString(text);
}
sf::FloatRect Button::rect() const
{
return _button_content.getGlobalBounds();
}
sf::Vector2f Button::position() const
{
return _button_content.getPosition();
}

View File

@ -1,32 +0,0 @@
#pragma once
#include "widget.h"
#include <functional>
#include <SFML/Graphics/RectangleShape.hpp>
#include <SFML/Graphics/Text.hpp>
class Button : public Widget
{
public:
explicit Button(const std::string& text, const std::shared_ptr<sf::Font>& font, unsigned int font_size);
virtual void input(const sf::Event& event) override = 0;
virtual void update(const sf::Time& dt) override final;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override final;
virtual void move(const sf::Vector2f& delta) override final;
virtual bool isUnderMouse(int mouse_x, int mouse_y) const override final;
virtual void setRect(const sf::FloatRect& rect) override;
virtual sf::FloatRect rect() const override;
virtual void setPosition(const sf::Vector2f& position) override;
virtual sf::Vector2f position() const override;
virtual void setText(const std::string& text);
protected:
sf::RectangleShape _button_content;
sf::Text _button_text;
std::shared_ptr<sf::Font> _font;
};

View File

@ -1,71 +0,0 @@
#include "cascademenubutton.h"
#include "menudrop.h"
CascadeMenuButton::CascadeMenuButton(const std::string& text, const std::shared_ptr<sf::Font> &font, unsigned int font_size) :
Button(text, font, font_size)
{
_color_idle = sf::Color(230, 230, 230);
_color_hover = sf::Color(84, 158, 253);
_button_content.setFillColor(_color_idle);
}
void CascadeMenuButton::input(const sf::Event& event)
{
if (!_submenu)
return;
switch (event.type)
{
default:
break;
case sf::Event::MouseMoved:
if (isUnderMouse(event.mouseMove.x, event.mouseMove.y))
{
_button_content.setFillColor(_color_hover);
_submenu->lock();
_submenu->setVisibility(true);
}
else
{
_submenu->unlock();
if (!_submenu->isVisible())
{
_button_content.setFillColor(sf::Color(_color_idle));
}
}
break;
}
}
void CascadeMenuButton::setRect(const sf::FloatRect& rect)
{
Button::setRect(rect);
resetRect();
}
void CascadeMenuButton::setSubmenu(const std::shared_ptr<MenuDrop>& submenu)
{
_submenu = submenu;
resetRect();
}
const std::shared_ptr<MenuDrop> CascadeMenuButton::submenu() const
{
return _submenu;
}
void CascadeMenuButton::resetRect()
{
if (_submenu)
{
_submenu->setPosition({_button_content.getPosition().x + _button_content.getSize().x,
_button_content.getPosition().y});
}
}
void CascadeMenuButton::setFillColors(sf::Color&& idle_color, sf::Color&& hover_color)
{
_color_idle = idle_color;
_color_hover = hover_color;
}

View File

@ -1,55 +0,0 @@
#include "editorwidget.h"
#include "core/editor.h"
EditorWidget::EditorWidget(Callbacks&& callbacks) :
_input(std::move(callbacks.onInput)),
_update(std::move(callbacks.onUpdate)),
_draw(std::move(callbacks.onDraw))
{}
void EditorWidget::input(const sf::Event& event)
{
_input(event);
}
void EditorWidget::update(const sf::Time& dt)
{
_update(dt);
}
void EditorWidget::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
_draw(target, states);
}
void EditorWidget::move(const sf::Vector2f& delta)
{
(void)delta;
// delegate to children
}
bool EditorWidget::isUnderMouse(int mouse_x, int mouse_y) const
{
return _parent->isUnderMouse(mouse_x, mouse_y);
}
void EditorWidget::setRect(const sf::FloatRect& rect)
{
(void)rect;
// basically useless beacuse editor widget fills the entire screen
}
sf::FloatRect EditorWidget::rect() const
{
return {};
}
void EditorWidget::setPosition(const sf::Vector2f& position)
{
(void)position;
}
sf::Vector2f EditorWidget::position() const
{
return {};
}

View File

@ -1,35 +0,0 @@
#pragma once
#include "widget.h"
class EditorWidget : public Widget
{
public:
struct Callbacks
{
std::function<void(const sf::Event& event)> onInput;
std::function<void(const sf::Time& dt)> onUpdate;
std::function<void(sf::RenderTarget& target, sf::RenderStates states)> onDraw;
};
explicit EditorWidget(Callbacks&& callbacks);
virtual void input(const sf::Event& event) override;
virtual void update(const sf::Time& dt) override;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
virtual void move(const sf::Vector2f& delta) override;
virtual bool isUnderMouse(int mouse_x, int mouse_y) const override;
virtual void setRect(const sf::FloatRect& rect) override;
virtual sf::FloatRect rect() const override;
virtual void setPosition(const sf::Vector2f& position) override;
virtual sf::Vector2f position() const override;
private:
std::function<void(const sf::Event& event)> _input;
std::function<void(const sf::Time& dt)> _update;
std::function<void(sf::RenderTarget& target, sf::RenderStates states)> _draw;
};

View File

@ -1,55 +0,0 @@
#include "group.h"
void Group::input(const sf::Event& event)
{
Widget::input(event);
}
void Group::update(const sf::Time& dt)
{
Widget::update(dt);
}
void Group::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
Widget::draw(target, states);
}
void Group::setRect(const sf::FloatRect& rect)
{
_rect = rect;
}
void Group::setPosition(const sf::Vector2f& position)
{
_rect.top = position.y;
_rect.left = position.x;
}
void Group::move(const sf::Vector2f& delta)
{
_rect.top += delta.y;
_rect.left += delta.x;
Widget::move(delta);
}
bool Group::isUnderMouse(int mouse_x, int mouse_y) const
{
return _rect.contains(mouse_x, mouse_y);
}
sf::FloatRect Group::rect() const
{
return _rect;
}
sf::Vector2f Group::position() const
{
return sf::Vector2f
{
_rect.top,
_rect.left
};
}

View File

@ -1,23 +0,0 @@
#pragma once
#include "widget.h"
class Group : public Widget
{
public:
virtual void input(const sf::Event& event) override;
virtual void update(const sf::Time& dt) override;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
virtual void move(const sf::Vector2f& delta) override;
virtual bool isUnderMouse(int mouse_x, int mouse_y) const override;
virtual void setRect(const sf::FloatRect& rect) override;
virtual sf::FloatRect rect() const override;
virtual void setPosition(const sf::Vector2f& position) override;
virtual sf::Vector2f position() const override;
private:
sf::FloatRect _rect;
};

View File

@ -1,125 +0,0 @@
#include "menubar.h"
#include "iostream"
MenuBar::MenuBar(const std::shared_ptr<sf::Font>& font) :
_font(font),
_amount_buttons(0),
_button_width(170)
{
_bar_rect.setFillColor(sf::Color(88, 57, 107));
}
void MenuBar::input(const sf::Event &event)
{
switch (event.type)
{
default:
break;
case sf::Event::MouseButtonReleased:
if (!isUnderMouse(event.mouseButton.x, event.mouseButton.y))
{
for (auto& submenu : _submenus)
submenu->unlock();
}
break;
}
Widget::input(event);
}
void MenuBar::update(const sf::Time& dt)
{
Widget::update(dt);
}
void MenuBar::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
if (_is_visible)
target.draw(_bar_rect, states);
Widget::draw(target, states);
}
void MenuBar::setRect(const sf::FloatRect& rect)
{
_bar_rect.setPosition(rect.left, rect.top);
_bar_rect.setSize({rect.width, rect.height});
// Buttons will not resize
}
void MenuBar::setPosition(const sf::Vector2f& position)
{
_bar_rect.setPosition(position);
}
void MenuBar::move(const sf::Vector2f &delta)
{
_bar_rect.move(delta);
Widget::move(delta);
for (auto& menu : _submenus)
menu->move(delta);
}
bool MenuBar::isUnderMouse(int mouse_x, int mouse_y) const
{
bool bar_under_mouse = _bar_rect.getGlobalBounds().contains(mouse_x, mouse_y);
bool submenus_under_mouse = std::any_of(_children.begin(), _children.end(),
[x=mouse_x, y=mouse_y](const auto& child)
{
return child->isUnderMouse(x, y);
});
return bar_under_mouse || submenus_under_mouse;
}
void MenuBar::addRootSubMenu(std::string name, const std::shared_ptr<MenuDrop>& submenu)
{
const auto new_button = std::make_shared<PushButton>(name, _font);
std::size_t current_index = _amount_buttons;
new_button->setRect(sf::FloatRect(current_index * _button_width, 0, _button_width, _bar_rect.getSize().y));
new_button->setCallback([submenu=submenu]()
{
submenu->setVisibility(true);
submenu->lock();
});
submenu->setPosition({static_cast<float>(current_index * _button_width),
_bar_rect.getSize().y});
new_button->setFillColors(sf::Color(171, 141, 189), sf::Color(48, 27, 57));
addChild(new_button);
addChild(submenu);
_submenus.emplace_back(submenu);
++_amount_buttons;
}
void MenuBar::addDependentSubmenu(const std::shared_ptr<MenuDrop> &submenu)
{
_submenus.emplace_back(submenu);;
}
void MenuBar::setVisibility(bool is_visible)
{
Widget::setVisibility(is_visible);
for (auto& submenu : _submenus)
submenu->setVisibility(false);
}
sf::FloatRect MenuBar::rect() const
{
return _bar_rect.getGlobalBounds();
}
sf::Vector2f MenuBar::position() const
{
return _bar_rect.getPosition();
}

View File

@ -1,37 +0,0 @@
#pragma once
#include "widget.h"
#include "menudrop.h"
#include "button.h"
#include <SFML/Graphics/RectangleShape.hpp>
class MenuBar : public Widget
{
public:
explicit MenuBar(const std::shared_ptr<sf::Font>& font);
virtual void input(const sf::Event& event) override;
virtual void update(const sf::Time& dt) override;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
virtual void move(const sf::Vector2f& delta) override;
virtual bool isUnderMouse(int mouse_x, int mouse_y) const override;
virtual void setVisibility(bool is_visible = true) override;
virtual void setRect(const sf::FloatRect& rect) override;
virtual sf::FloatRect rect() const override;
virtual void setPosition(const sf::Vector2f& position) override;
virtual sf::Vector2f position() const override;
void addRootSubMenu(std::string name, const std::shared_ptr<MenuDrop>& submenu);
void addDependentSubmenu(const std::shared_ptr<MenuDrop>& submenu);
private:
std::shared_ptr<sf::Font> _font;
sf::RectangleShape _bar_rect;
std::size_t _amount_buttons;
std::size_t _button_width;
std::vector<std::shared_ptr<MenuDrop>> _submenus;
};

View File

@ -1,45 +0,0 @@
#pragma once
#include "widget.h"
#include "pushbutton.h"
#include "cascademenubutton.h"
#include <SFML/Graphics/RectangleShape.hpp>
class MenuDrop : public Widget
{
public:
explicit MenuDrop();
virtual void input(const sf::Event& event) override;
virtual void update(const sf::Time& dt) override;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
virtual void move(const sf::Vector2f& delta) override;
virtual bool isUnderMouse(int mouse_x, int mouse_y) const override;
virtual void setVisibility(bool is_visible = true) override;
virtual void setRect(const sf::FloatRect& rect) override;
virtual sf::FloatRect rect() const override;
virtual void setPosition(const sf::Vector2f& position) override;
virtual sf::Vector2f position() const override;
void addPushButton(const std::shared_ptr<PushButton>& button);
void addCascadeButton(const std::shared_ptr<CascadeMenuButton>& button);
void addSeparator();
void lock();
void unlock();
bool isLocked() const;
private:
sf::RectangleShape _content_rect;
bool _is_locked;
std::size_t _button_height;
std::size_t _button_index;
std::vector<std::shared_ptr<MenuDrop>> _submenus;
void add(const std::shared_ptr<Widget>& widget);
bool hasActiveSubmenus() const;
};

View File

@ -1,48 +0,0 @@
#include "menuseparator.h"
void MenuSeparator::input(const sf::Event& event)
{
Widget::input(event);
}
void MenuSeparator::update(const sf::Time& dt)
{
Widget::update(dt);
}
void MenuSeparator::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
target.draw(_line, states);
}
void MenuSeparator::setRect(const sf::FloatRect& rect)
{
_rect = rect;
//_line
}
void MenuSeparator::setPosition(const sf::Vector2f& position)
{
(void)position;
}
void MenuSeparator::move(const sf::Vector2f& delta)
{
(void)delta;
}
bool MenuSeparator::isUnderMouse(int mouse_x, int mouse_y) const
{
return _is_visible && _rect.contains(mouse_x, mouse_y);
}
sf::FloatRect MenuSeparator::rect() const
{
return {};
}
sf::Vector2f MenuSeparator::position() const
{
return {};
}

View File

@ -1,26 +0,0 @@
#pragma once
#include "widget.h"
#include <SFML/Graphics/VertexArray.hpp>
class MenuSeparator : public Widget
{
public:
virtual void input(const sf::Event& event) override;
virtual void update(const sf::Time& dt) override;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
virtual void move(const sf::Vector2f& delta) override;
virtual bool isUnderMouse(int mouse_x, int mouse_y) const override;
virtual void setRect(const sf::FloatRect& rect) override;
virtual sf::FloatRect rect() const override;
virtual void setPosition(const sf::Vector2f& position) override;
virtual sf::Vector2f position() const override;
private:
sf::VertexArray _line;
sf::FloatRect _rect;
};

Some files were not shown because too many files have changed in this diff Show More