Mercurial > malikania
changeset 52:4bc4732fa1dd
Client: add basic button, closes #601
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 15 Dec 2016 13:46:46 +0100 |
parents | d04a4915be2b |
children | fe7e3524e571 |
files | client/CMakeLists.txt client/main.cpp libclient/CMakeLists.txt libclient/assets/dejavu_sans.ttf libclient/malikania/backend/sdl/window_backend.cpp libclient/malikania/backend/sdl/window_backend.hpp libclient/malikania/button.cpp libclient/malikania/button.hpp libclient/malikania/frame.cpp libclient/malikania/frame.hpp libclient/malikania/grid_layout.cpp libclient/malikania/grid_layout.hpp libclient/malikania/key.hpp libclient/malikania/layout.hpp libclient/malikania/mouse.hpp libclient/malikania/theme.cpp libclient/malikania/theme.hpp libclient/malikania/unique_layout.cpp libclient/malikania/unique_layout.hpp libclient/malikania/widget.cpp libclient/malikania/widget.hpp libclient/malikania/window.cpp libclient/malikania/window.hpp |
diffstat | 23 files changed, 2067 insertions(+), 39 deletions(-) [+] |
line wrap: on
line diff
--- a/client/CMakeLists.txt Thu Dec 15 13:43:09 2016 +0100 +++ b/client/CMakeLists.txt Thu Dec 15 13:46:46 2016 +0100 @@ -16,13 +16,15 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # -project(client) +project(mlk-client) set( - FILES + SOURCES main.cpp ) -add_executable(mlk-client ${FILES}) -target_include_directories(mlk-client PRIVATE ${client_SOURCE_DIR}) -target_link_libraries(mlk-client libclient-js) +malikania_define_executable( + TARGET mlk-client + SOURCES ${SOURCES} + LIBRARIES libclient-js +)
--- a/client/main.cpp Thu Dec 15 13:43:09 2016 +0100 +++ b/client/main.cpp Thu Dec 15 13:46:46 2016 +0100 @@ -16,7 +16,38 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <chrono> +#include <thread> + +#include "malikania/button.hpp" +#include "malikania/color.hpp" +#include "malikania/frame.hpp" +#include "malikania/point.hpp" +#include "malikania/unique_layout.hpp" +#include "malikania/window.hpp" + int main() { + mlk::window win; + + auto f = std::make_shared<mlk::frame>(); + auto b = std::make_shared<mlk::button>("click me!"); + auto l = std::make_shared<mlk::unique_layout>(b); + + b->on_clicked.connect([] { + puts("clicked!!!!"); + }); + f->move({50, 50}); + f->set_layout(l); + win.add_frame(f); + + while (win.is_open()) { + win.poll(); + win.set_drawing_color({255, 255, 255, 255}); + win.clear(); + win.draw_frames(); + win.present(); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } }
--- a/libclient/CMakeLists.txt Thu Dec 15 13:43:09 2016 +0100 +++ b/libclient/CMakeLists.txt Thu Dec 15 13:46:46 2016 +0100 @@ -22,14 +22,23 @@ HEADERS ${libclient_SOURCE_DIR}/malikania/animation.hpp ${libclient_SOURCE_DIR}/malikania/animator.hpp + ${libclient_SOURCE_DIR}/malikania/button.hpp ${libclient_SOURCE_DIR}/malikania/color.hpp ${libclient_SOURCE_DIR}/malikania/font.hpp + ${libclient_SOURCE_DIR}/malikania/frame.hpp +# ${libclient_SOURCE_DIR}/malikania/grid_layout.hpp ${libclient_SOURCE_DIR}/malikania/image.hpp + ${libclient_SOURCE_DIR}/malikania/key.hpp + ${libclient_SOURCE_DIR}/malikania/layout.hpp ${libclient_SOURCE_DIR}/malikania/line.hpp + ${libclient_SOURCE_DIR}/malikania/mouse.hpp ${libclient_SOURCE_DIR}/malikania/point.hpp ${libclient_SOURCE_DIR}/malikania/rectangle.hpp ${libclient_SOURCE_DIR}/malikania/size.hpp ${libclient_SOURCE_DIR}/malikania/sprite.hpp + ${libclient_SOURCE_DIR}/malikania/theme.hpp + ${libclient_SOURCE_DIR}/malikania/unique_layout.hpp + ${libclient_SOURCE_DIR}/malikania/widget.hpp ${libclient_SOURCE_DIR}/malikania/window.hpp ${libclient_SOURCE_DIR}/malikania/${WITH_BACKEND_DIR}/font_backend.hpp ${libclient_SOURCE_DIR}/malikania/${WITH_BACKEND_DIR}/image_backend.hpp @@ -39,11 +48,17 @@ set( SOURCES ${libclient_SOURCE_DIR}/malikania/animator.cpp + ${libclient_SOURCE_DIR}/malikania/button.cpp ${libclient_SOURCE_DIR}/malikania/client_resources_loader.cpp ${libclient_SOURCE_DIR}/malikania/color.cpp ${libclient_SOURCE_DIR}/malikania/font.cpp + ${libclient_SOURCE_DIR}/malikania/frame.cpp +# ${libclient_SOURCE_DIR}/malikania/grid_layout.cpp ${libclient_SOURCE_DIR}/malikania/image.cpp ${libclient_SOURCE_DIR}/malikania/sprite.cpp + ${libclient_SOURCE_DIR}/malikania/theme.cpp + ${libclient_SOURCE_DIR}/malikania/unique_layout.cpp + ${libclient_SOURCE_DIR}/malikania/widget.cpp ${libclient_SOURCE_DIR}/malikania/window.cpp ${libclient_SOURCE_DIR}/malikania/${WITH_BACKEND_DIR}/font_backend.cpp ${libclient_SOURCE_DIR}/malikania/${WITH_BACKEND_DIR}/image_backend.cpp @@ -75,6 +90,7 @@ PROJECT libclient TARGET libclient SOURCES ${HEADERS} ${SOURCES} + ASSETS ${libclient_SOURCE_DIR}/assets/dejavu_sans.ttf PUBLIC_INCLUDES $<BUILD_INTERFACE:${libclient_SOURCE_DIR}/malikania/${WITH_BACKEND_DIR}> $<BUILD_INTERFACE:${libclient_SOURCE_DIR}/malikania>
--- a/libclient/malikania/backend/sdl/window_backend.cpp Thu Dec 15 13:43:09 2016 +0100 +++ b/libclient/malikania/backend/sdl/window_backend.cpp Thu Dec 15 13:46:46 2016 +0100 @@ -16,21 +16,380 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <cassert> +#include <stdexcept> +#include <unordered_map> + #include <SDL.h> #include <SDL_ttf.h> -#include <stdexcept> - #include <malikania/color.hpp> +#include <malikania/key.hpp> #include <malikania/line.hpp> #include <malikania/point.hpp> #include <malikania/rectangle.hpp> #include "font_backend.hpp" #include "window_backend.hpp" +#include "window.hpp" namespace mlk { +namespace { + +/* + * conversion maps + * ------------------------------------------------------------------ + * + * There is a difference between scancode and key codes. The scancode is the + * key located on the keyboard which is always the same, the key code is the + * translated to the user layout. + * + * For example, on azerty, hitting the 'a' key makes a key code of 'a' but a + * scancode of 'q'. + * + * - scancodes_map : convert SDL scancode do key + * - keycodes_map : convert SDL key code to key + * - modifiers_map : convert masks + * - button_map : convert SDL mouse buttons + */ + +const std::unordered_map<SDL_Keycode, key> scancodes_map{ + { SDL_SCANCODE_A, key::a }, + { SDL_SCANCODE_B, key::b }, + { SDL_SCANCODE_C, key::c }, + { SDL_SCANCODE_D, key::d }, + { SDL_SCANCODE_E, key::e }, + { SDL_SCANCODE_F, key::f }, + { SDL_SCANCODE_G, key::g }, + { SDL_SCANCODE_H, key::h }, + { SDL_SCANCODE_I, key::i }, + { SDL_SCANCODE_J, key::j }, + { SDL_SCANCODE_K, key::k }, + { SDL_SCANCODE_L, key::l }, + { SDL_SCANCODE_M, key::m }, + { SDL_SCANCODE_N, key::n }, + { SDL_SCANCODE_O, key::o }, + { SDL_SCANCODE_P, key::p }, + { SDL_SCANCODE_Q, key::q }, + { SDL_SCANCODE_R, key::r }, + { SDL_SCANCODE_S, key::s }, + { SDL_SCANCODE_T, key::t }, + { SDL_SCANCODE_U, key::u }, + { SDL_SCANCODE_V, key::v }, + { SDL_SCANCODE_W, key::w }, + { SDL_SCANCODE_X, key::x }, + { SDL_SCANCODE_Y, key::y }, + { SDL_SCANCODE_Z, key::z }, + { SDL_SCANCODE_1, key::one }, + { SDL_SCANCODE_2, key::two }, + { SDL_SCANCODE_3, key::three }, + { SDL_SCANCODE_4, key::four }, + { SDL_SCANCODE_5, key::five }, + { SDL_SCANCODE_6, key::six }, + { SDL_SCANCODE_7, key::seven }, + { SDL_SCANCODE_8, key::eight }, + { SDL_SCANCODE_9, key::nine }, + { SDL_SCANCODE_0, key::zero }, + { SDL_SCANCODE_RETURN, key::enter }, + { SDL_SCANCODE_ESCAPE, key::escape }, + { SDL_SCANCODE_BACKSPACE, key::backspace }, + { SDL_SCANCODE_TAB, key::tab }, + { SDL_SCANCODE_SPACE, key::space }, + { SDL_SCANCODE_MINUS, key::minus }, + { SDL_SCANCODE_EQUALS, key::equals }, + { SDL_SCANCODE_LEFTBRACKET, key::left_bracket }, + { SDL_SCANCODE_RIGHTBRACKET, key::right_bracket }, + { SDL_SCANCODE_BACKSLASH, key::backslash }, + { SDL_SCANCODE_NONUSHASH, key::hash }, + { SDL_SCANCODE_SEMICOLON, key::semicolon }, + { SDL_SCANCODE_APOSTROPHE, key::apostrophe }, + { SDL_SCANCODE_GRAVE, key::grave }, + { SDL_SCANCODE_COMMA, key::comma }, + { SDL_SCANCODE_PERIOD, key::period }, + { SDL_SCANCODE_SLASH, key::slash }, + { SDL_SCANCODE_CAPSLOCK, key::caps_lock }, + { SDL_SCANCODE_F1, key::f1 }, + { SDL_SCANCODE_F2, key::f2 }, + { SDL_SCANCODE_F3, key::f3 }, + { SDL_SCANCODE_F4, key::f4 }, + { SDL_SCANCODE_F5, key::f5 }, + { SDL_SCANCODE_F6, key::f6 }, + { SDL_SCANCODE_F7, key::f7 }, + { SDL_SCANCODE_F8, key::f8 }, + { SDL_SCANCODE_F9, key::f9 }, + { SDL_SCANCODE_F10, key::f10 }, + { SDL_SCANCODE_F11, key::f11 }, + { SDL_SCANCODE_F12, key::f12 }, + { SDL_SCANCODE_F13, key::f13 }, + { SDL_SCANCODE_F14, key::f14 }, + { SDL_SCANCODE_F15, key::f15 }, + { SDL_SCANCODE_F16, key::f16 }, + { SDL_SCANCODE_F17, key::f17 }, + { SDL_SCANCODE_F18, key::f18 }, + { SDL_SCANCODE_F19, key::f19 }, + { SDL_SCANCODE_F20, key::f20 }, + { SDL_SCANCODE_F21, key::f21 }, + { SDL_SCANCODE_F22, key::f22 }, + { SDL_SCANCODE_F23, key::f23 }, + { SDL_SCANCODE_F24, key::f24 }, + { SDL_SCANCODE_PRINTSCREEN, key::print_screen }, + { SDL_SCANCODE_SCROLLLOCK, key::scroll_lock }, + { SDL_SCANCODE_PAUSE, key::pause }, + { SDL_SCANCODE_INSERT, key::insert }, + { SDL_SCANCODE_HOME, key::home }, + { SDL_SCANCODE_PAGEUP, key::page_up }, + { SDL_SCANCODE_PAGEDOWN, key::page_down }, + { SDL_SCANCODE_DELETE, key::del }, + { SDL_SCANCODE_END, key::end }, + { SDL_SCANCODE_RIGHT, key::right }, + { SDL_SCANCODE_LEFT, key::left }, + { SDL_SCANCODE_DOWN, key::down }, + { SDL_SCANCODE_UP, key::up }, + { SDL_SCANCODE_KP_DIVIDE, key::kp_divide }, + { SDL_SCANCODE_KP_MULTIPLY, key::kp_multiply }, + { SDL_SCANCODE_KP_MINUS, key::kp_minus }, + { SDL_SCANCODE_KP_PLUS, key::kp_plus }, + { SDL_SCANCODE_KP_ENTER, key::kp_enter }, + { SDL_SCANCODE_KP_1, key::kp_one }, + { SDL_SCANCODE_KP_2, key::kp_two }, + { SDL_SCANCODE_KP_3, key::kp_three }, + { SDL_SCANCODE_KP_4, key::kp_four }, + { SDL_SCANCODE_KP_5, key::kp_five }, + { SDL_SCANCODE_KP_6, key::kp_six }, + { SDL_SCANCODE_KP_7, key::kp_seven }, + { SDL_SCANCODE_KP_8, key::kp_eight }, + { SDL_SCANCODE_KP_9, key::kp_nine }, + { SDL_SCANCODE_KP_0, key::kp_zero }, + { SDL_SCANCODE_MUTE, key::mute }, + { SDL_SCANCODE_VOLUMEUP, key::volume_up }, + { SDL_SCANCODE_VOLUMEDOWN, key::volume_down }, + { SDL_SCANCODE_LCTRL, key::left_control }, + { SDL_SCANCODE_LALT, key::left_alt }, + { SDL_SCANCODE_LSHIFT, key::left_shift }, + { SDL_SCANCODE_LGUI, key::left_super }, + { SDL_SCANCODE_RCTRL, key::right_control }, + { SDL_SCANCODE_RALT, key::right_alt }, + { SDL_SCANCODE_RSHIFT, key::right_shift }, + { SDL_SCANCODE_RGUI, key::right_super } +}; + +const std::unordered_map<SDL_Keycode, key> keycodes_map{ + { SDLK_RETURN, key::enter }, + { SDLK_ESCAPE, key::escape }, + { SDLK_BACKSPACE, key::backspace }, + { SDLK_TAB, key::tab }, + { SDLK_SPACE, key::space }, + { SDLK_EXCLAIM, key::exclaim }, + { SDLK_QUOTEDBL, key::double_quote }, + { SDLK_HASH, key::hash }, + { SDLK_PERCENT, key::percent }, + { SDLK_DOLLAR, key::dollar }, + { SDLK_AMPERSAND, key::ampersand }, + { SDLK_QUOTE, key::quote }, + { SDLK_LEFTPAREN, key::left_parenthese }, + { SDLK_RIGHTPAREN, key::right_parenthese }, + { SDLK_ASTERISK, key::asterisk }, + { SDLK_PLUS, key::plus }, + { SDLK_COMMA, key::comma }, + { SDLK_MINUS, key::minus }, + { SDLK_PERIOD, key::period }, + { SDLK_SLASH, key::slash }, + { SDLK_0, key::zero }, + { SDLK_1, key::one }, + { SDLK_2, key::two }, + { SDLK_3, key::three }, + { SDLK_4, key::four }, + { SDLK_5, key::five }, + { SDLK_6, key::six }, + { SDLK_7, key::seven }, + { SDLK_8, key::eight }, + { SDLK_9, key::nine }, + { SDLK_COLON, key::colon }, + { SDLK_SEMICOLON, key::semicolon }, + { SDLK_LESS, key::less }, + { SDLK_EQUALS, key::equals }, + { SDLK_GREATER, key::greater }, + { SDLK_QUESTION, key::question }, + { SDLK_AT, key::at }, + { SDLK_LEFTBRACKET, key::left_bracket }, + { SDLK_BACKSLASH, key::backslash }, + { SDLK_RIGHTBRACKET, key::right_bracket }, + { SDLK_CARET, key::caret }, + { SDLK_UNDERSCORE, key::underscore }, + { SDLK_BACKQUOTE, key::back_quote }, + { SDLK_a, key::a }, + { SDLK_b, key::b }, + { SDLK_c, key::c }, + { SDLK_d, key::d }, + { SDLK_e, key::e }, + { SDLK_f, key::f }, + { SDLK_g, key::g }, + { SDLK_h, key::h }, + { SDLK_i, key::i }, + { SDLK_j, key::j }, + { SDLK_k, key::k }, + { SDLK_l, key::l }, + { SDLK_m, key::m }, + { SDLK_n, key::n }, + { SDLK_o, key::o }, + { SDLK_p, key::p }, + { SDLK_q, key::q }, + { SDLK_r, key::r }, + { SDLK_s, key::s }, + { SDLK_t, key::t }, + { SDLK_u, key::u }, + { SDLK_v, key::v }, + { SDLK_w, key::w }, + { SDLK_x, key::x }, + { SDLK_y, key::y }, + { SDLK_z, key::z }, + { SDLK_CAPSLOCK, key::caps_lock }, + { SDLK_F1, key::f1 }, + { SDLK_F2, key::f2 }, + { SDLK_F3, key::f3 }, + { SDLK_F4, key::f4 }, + { SDLK_F5, key::f5 }, + { SDLK_F6, key::f6 }, + { SDLK_F7, key::f7 }, + { SDLK_F8, key::f8 }, + { SDLK_F9, key::f9 }, + { SDLK_F10, key::f10 }, + { SDLK_F11, key::f11 }, + { SDLK_F12, key::f12 }, + { SDLK_F13, key::f13 }, + { SDLK_F14, key::f14 }, + { SDLK_F15, key::f15 }, + { SDLK_F16, key::f16 }, + { SDLK_F17, key::f17 }, + { SDLK_F18, key::f18 }, + { SDLK_F19, key::f19 }, + { SDLK_F20, key::f20 }, + { SDLK_F21, key::f21 }, + { SDLK_F22, key::f22 }, + { SDLK_F23, key::f23 }, + { SDLK_F24, key::f24 }, + { SDLK_PRINTSCREEN, key::print_screen }, + { SDLK_SCROLLLOCK, key::scroll_lock }, + { SDLK_PAUSE, key::pause }, + { SDLK_INSERT, key::insert }, + { SDLK_HOME, key::home }, + { SDLK_PAGEUP, key::page_up }, + { SDLK_PAGEDOWN, key::page_down }, + { SDLK_DELETE, key::del }, + { SDLK_END, key::end }, + { SDLK_RIGHT, key::right }, + { SDLK_LEFT, key::left }, + { SDLK_DOWN, key::down }, + { SDLK_UP, key::up }, + { SDLK_KP_DIVIDE, key::kp_divide }, + { SDLK_KP_MULTIPLY, key::kp_multiply }, + { SDLK_KP_MINUS, key::kp_minus }, + { SDLK_KP_PLUS, key::kp_plus }, + { SDLK_KP_ENTER, key::kp_enter }, + { SDLK_KP_1, key::kp_one }, + { SDLK_KP_2, key::kp_two }, + { SDLK_KP_3, key::kp_three }, + { SDLK_KP_4, key::kp_four }, + { SDLK_KP_5, key::kp_five }, + { SDLK_KP_6, key::kp_six }, + { SDLK_KP_7, key::kp_seven }, + { SDLK_KP_8, key::kp_eight }, + { SDLK_KP_9, key::kp_nine }, + { SDLK_KP_0, key::kp_zero }, + { SDLK_MUTE, key::mute }, + { SDLK_VOLUMEUP, key::volume_up }, + { SDLK_VOLUMEDOWN, key::volume_down }, + { SDLK_LCTRL, key::left_control }, + { SDLK_LALT, key::left_alt }, + { SDLK_LSHIFT, key::left_shift }, + { SDLK_LGUI, key::left_super }, + { SDLK_RCTRL, key::right_control }, + { SDLK_RALT, key::right_alt }, + { SDLK_RSHIFT, key::right_shift }, + { SDLK_RGUI, key::right_super } +}; + +const std::unordered_map<SDL_Keymod, mod> modifiers_map{ + { KMOD_LCTRL, mod::left_control }, + { KMOD_LALT, mod::left_alt }, + { KMOD_LSHIFT, mod::left_shift }, + { KMOD_LGUI, mod::left_super }, + { KMOD_RCTRL, mod::right_control }, + { KMOD_RALT, mod::right_alt }, + { KMOD_RSHIFT, mod::right_shift }, + { KMOD_RGUI, mod::right_super }, + { KMOD_NUM, mod::num_lock }, + { KMOD_CAPS, mod::caps_lock } +}; + +const std::unordered_map<Uint32, mouse> button_map{ + { SDL_BUTTON_LEFT, mouse::left }, + { SDL_BUTTON_RIGHT, mouse::right }, + { SDL_BUTTON_MIDDLE, mouse::middle } +}; + +} // !namespace + +void window::backend_impl::handle_key(window& self, const SDL_Event& ev) +{ + assert(ev.type == SDL_KEYDOWN || ev.type == SDL_KEYUP); + + // Key and scan code. + auto kc = keycodes_map.find(ev.key.keysym.sym); + auto sc = scancodes_map.find(ev.key.keysym.scancode); + + if (kc == keycodes_map.end() || sc == scancodes_map.end()) { + return; + } + + key_event kev{kc->second, sc->second, mod::none}; + + // Modifier is a mask. + for (const auto& pair : modifiers_map) { + if (ev.key.keysym.mod & pair.first) { + kev.modifiers |= pair.second; + } + } + + if (ev.type == SDL_KEYDOWN) { + self.handle_key_down(kev); + } else { + self.handle_key_up(kev); + } +} + +void window::backend_impl::handle_mouse(window& self, const SDL_Event& ev) +{ + assert(ev.type == SDL_MOUSEBUTTONDOWN || ev.type == SDL_MOUSEBUTTONUP); + + auto which = button_map.find(ev.button.button); + + if (which == button_map.end()) { + return; + } + + mouse_click_event mev{ + which->second, + point(ev.button.x, ev.button.y) + }; + + if (ev.type == SDL_MOUSEBUTTONDOWN) { + self.handle_mouse_down(mev); + } else { + self.handle_mouse_up(mev); + } +} + +void window::backend_impl::handle_mouse_wheel(window& self, const SDL_Event& ev) +{ + assert(ev.type == SDL_MOUSEWHEEL); + + mouse_wheel_event wev{{ev.wheel.x, ev.wheel.y}}; + + self.handle_mouse_wheel(wev); +} + window::backend_impl::backend_impl(window&, unsigned width, unsigned height, const std::string& title) : m_window(nullptr, nullptr) , m_renderer(nullptr, nullptr) @@ -61,27 +420,6 @@ } } -void window::backend_impl::poll(window&) -{ - SDL_Event event; - - while (SDL_PollEvent(&event)) { - switch (event.type) { - case SDL_KEYUP: - //self.onKeyUp(event.key.keysym.sym); - break; - case SDL_KEYDOWN: - //self.onKeyDown(event.key.keysym.sym); - break; - case SDL_QUIT: - //self.onQuit(); - break; - default: - break; - } - } -} - void window::backend_impl::clear() { SDL_RenderClear(m_renderer.get()); @@ -267,4 +605,30 @@ { } +void window::backend_impl::poll(window& self) +{ + SDL_Event event; + + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_KEYUP: + case SDL_KEYDOWN: + handle_key(self, event); + break; + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + handle_mouse(self, event); + break; + case SDL_MOUSEWHEEL: + handle_mouse_wheel(self, event); + break; + case SDL_QUIT: + self.handle_quit(); + break; + default: + break; + } + } +} + } // !mlk
--- a/libclient/malikania/backend/sdl/window_backend.hpp Thu Dec 15 13:43:09 2016 +0100 +++ b/libclient/malikania/backend/sdl/window_backend.hpp Thu Dec 15 13:46:46 2016 +0100 @@ -33,6 +33,10 @@ std::unique_ptr<SDL_Window, void (*)(SDL_Window *)> m_window; std::unique_ptr<SDL_Renderer, void (*)(SDL_Renderer *)> m_renderer; + void handle_key(window&, const SDL_Event&); + void handle_mouse(window&, const SDL_Event&); + void handle_mouse_wheel(window&, const SDL_Event&); + public: backend_impl(window& self, unsigned width, unsigned height, const std::string& title); @@ -41,8 +45,6 @@ return m_renderer.get(); } - void poll(window& self); - void close(); void clear(); @@ -72,6 +74,8 @@ void draw_text(const std::string& text, font& font, const rectangle& rectangle); void draw_text(const std::string& text, font& font, const point& point); + + void poll(window &self); }; } // !mlk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/button.cpp Thu Dec 15 13:46:46 2016 +0100 @@ -0,0 +1,47 @@ +/* + * button.cpp -- GUI button element + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "button.hpp" +#include "theme.hpp" +#include "window.hpp" + +namespace mlk { + +button::button(std::string text) + : m_text(std::move(text)) +{ +} + +void button::handle_mouse_down(const mouse_click_event& ev) +{ + if (ev.button == mouse::left) { + on_clicked(); + } +} + +void button::draw(window& w, const rectangle& rect) +{ + w.theme().draw_button(w, *this, rect); +} + +mlk::size button::size(window& w) const noexcept +{ + return w.theme().size_button(*this); +} + +} // !mlk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/button.hpp Thu Dec 15 13:46:46 2016 +0100 @@ -0,0 +1,97 @@ +/* + * button.hpp -- GUI button element + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_BUTTON_HPP +#define MALIKANIA_CLIENT_BUTTON_HPP + +/** + * \file button.hpp + * \brief GUI button element. + */ + +#include <boost/signals2.hpp> + +#include <string> + +#include "widget.hpp" + +namespace mlk { + +/** + * \brief Basic button element. + */ +class button : public widget { +public: + boost::signals2::signal<void()> on_clicked; + boost::signals2::signal<void()> on_released; + +private: + std::string m_text; + +public: + /** + * Default constructor with optional text. + * + * \param text the text + */ + button(std::string text = ""); + + /** + * Get the button text. + * + * \return the text + */ + inline const std::string& text() const noexcept + { + return m_text; + } + + /** + * Set the button text. + * + * \param text the text + */ + inline void set_text(std::string text) noexcept + { + m_text = std::move(text); + } + + /** + * \copydoc widget::handle_mouse_down + */ + void handle_mouse_down(const mouse_click_event& ev) override; + + /** + * Bring back other functions. + */ + using widget::draw; + + /** + * \copydoc widget::draw + */ + void draw(window& w, const rectangle& rect) override; + + /** + * \copydoc widget::size + */ + mlk::size size(window& w) const noexcept override; +}; + +} // !mlk + +#endif // !MALIKANIA_CLIENT_BUTTON_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/frame.cpp Thu Dec 15 13:46:46 2016 +0100 @@ -0,0 +1,45 @@ +/* + * frame.cpp -- top level GUI frame + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "layout.hpp" +#include "frame.hpp" +#include "point.hpp" +#include "rectangle.hpp" +#include "theme.hpp" +#include "window.hpp" + +namespace mlk { + +mlk::size frame::size(window &win) +{ + return m_layout ? m_layout->size(win) : mlk::size(); +} + +void frame::draw(window& win) +{ + if (m_layout) { + win.theme().draw_frame(win, *this); + } +} + +void frame::move(point pos) +{ + m_position = std::move(pos); +} + +} // !mlk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/frame.hpp Thu Dec 15 13:46:46 2016 +0100 @@ -0,0 +1,174 @@ +/* + * frame.hpp -- top level GUI frame + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_FRAME_HPP +#define MALIKANIA_CLIENT_FRAME_HPP + +/** + * \file frame.hpp + * \brief Top level GUI frame. + */ + +#include <memory> + +#include "point.hpp" +#include "size.hpp" + +namespace mlk { + +class layout; +class point; +class window; + +/** + * \brief Top level GUI frame. + */ +class frame { +private: + std::shared_ptr<mlk::layout> m_layout; + mlk::point m_position; + mlk::size m_padding{10, 10}; + +public: + /** + * Create a frame with an optional layout. + * + * \param layout the optional layout + */ + inline frame(std::shared_ptr<mlk::layout> layout = nullptr) noexcept + : m_layout(std::move(layout)) + { + } + + /** + * Virtual destructor defaulted. + */ + virtual ~frame() = default; + + /** + * Get the current layout. + * + * return the layout + */ + inline const std::shared_ptr<mlk::layout>& layout() const noexcept + { + return m_layout; + } + + /** + * Overloaded function. + * + * \return the layout + */ + inline std::shared_ptr<mlk::layout>& layout() noexcept + { + return m_layout; + } + + /** + * Change the current frame layout. + * + * \param layout the new layout (may be null) + */ + inline void set_layout(std::shared_ptr<mlk::layout> layout) noexcept + { + m_layout = std::move(layout); + } + + /** + * Get the current frame position. + * + * \return the frame position + */ + inline const point& position() const noexcept + { + return m_position; + } + + /** + * Overloaded function. + * + * \return the position + */ + inline point& position() noexcept + { + return m_position; + } + + /** + * Get the frame padding. + * + * \return the frame padding + */ + inline const mlk::size& padding() const noexcept + { + return m_padding; + } + + /** + * Overloaded function. + * + * \return the padding + */ + inline mlk::size& padding() noexcept + { + return m_padding; + } + + /** + * Set the frame padding. + * + * \param padding the padding + */ + inline void set_padding(mlk::size padding) noexcept + { + m_padding = std::move(padding); + } + + /** + * Compute the total frame size. + * + * If no layout is attached, the frame returns a null size. Otherwise, the + * default implementation returns `layout()->size()`. + * + * \param win the window + * \return the size required to draw this frame + */ + virtual mlk::size size(window& win); + + /** + * Draw the frame and its content. + * + * If no layout is attached, the function is a no-op. Otherwise the default + * implementation calls `win.theme().draw_frame(*this)`. + * + * \param win the window + */ + virtual void draw(window& win); + + /** + * Move the frame to somewhere else. + * + * \param pos the new position + */ + virtual void move(point pos); +}; + +} // !mlk + +#endif // !MALIKANIA_CLIENT_FRAME_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/grid_layout.cpp Thu Dec 15 13:46:46 2016 +0100 @@ -0,0 +1,112 @@ +/* + * grid_layout.cpp -- basic grid layout + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <algorithm> +#include <numeric> + +#include "grid_layout.hpp" +#include "size.hpp" +#include "widget.hpp" + +namespace mlk { + +unsigned grid_layout::index(unsigned r, unsigned c) const noexcept +{ + return r * m_cols + c; +} + +void grid_layout::update_rsize(window& win) noexcept +{ + for (unsigned r = 0; r < m_rows; ++r) { + m_min_rsize[r] = 0; + + for (unsigned c = 0; c < m_cols; ++c) { + auto idx = index(r, c); + + if (!m_widgets[idx]) { + continue; + } + + auto size = m_widgets[index(r, c)]->size(win); + + if (size.height() > m_min_rsize[r]) { + m_min_rsize[r] = size.height(); + } + } + } +} + +void grid_layout::update_csize(window& win) noexcept +{ + for (unsigned c = 0; c < m_cols; ++c) { + m_min_csize[c] = 0; + + for (unsigned r = 0; r < m_rows; ++r) { + auto idx = index(r, c); + + if (!m_widgets[idx]) { + continue; + } + + auto size = m_widgets[index(r, c)]->size(win); + + if (size.width() > m_min_csize[c]) { + m_min_csize[c] = size.width(); + } + } + } +} + +grid_layout::grid_layout(unsigned rows, unsigned columns) + : m_rows(rows) + , m_cols(columns) +{ + m_widgets.resize(rows * columns); + m_min_rsize.resize(rows); + m_min_csize.resize(columns); +} + +void grid_layout::add_widget(unsigned r, unsigned c, std::shared_ptr<widget> w) +{ + m_widgets[index(r, c)] = std::move(w); +} + +void grid_layout::remove_widget(unsigned r, unsigned c) +{ + m_widgets[index(r, c)] = nullptr; +} + +void grid_layout::remove_widget(std::shared_ptr<widget> w) +{ + m_widgets.erase(std::remove(m_widgets.begin(), m_widgets.end(), w), m_widgets.end()); +} + +mlk::size grid_layout::size(window& win) const noexcept +{ + return { + std::accumulate(m_min_csize.begin(), m_min_csize.end(), 0) + (m_rows * 10), + std::accumulate(m_min_rsize.begin(), m_min_rsize.end(), 0) + (m_cols * 10) + }; +} + +void grid_layout::draw(window &win, const rectangle &dst) +{ + +} + +} // !mlk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/grid_layout.hpp Thu Dec 15 13:46:46 2016 +0100 @@ -0,0 +1,70 @@ +/* + * grid_layout.hpp -- basic grid layout + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_GRID_LAYOUT_HPP +#define MALIKANIA_CLIENT_GRID_LAYOUT_HPP + +#include <memory> +#include <vector> + +#include "layout.hpp" + +namespace mlk { + +class widget; + +class grid_layout : public layout { +private: + // Dimensions. + unsigned m_rows; + unsigned m_cols; + + // Widgets. + std::vector<std::shared_ptr<widget>> m_widgets; + + /* + * Track maximum size by rows/columns to determine the minimum whole + * layout size. + * + * It's only used in draw() but kept as member variables to avoid useless + * reallocation on each frame. + */ + std::vector<unsigned> m_min_rsize; + std::vector<unsigned> m_min_csize; + + unsigned index(unsigned, unsigned) const noexcept; + void update_rsize(window&) noexcept; + void update_csize(window&) noexcept; + +public: + grid_layout(unsigned rows, unsigned columns); + + void add_widget(unsigned r, unsigned c, std::shared_ptr<widget> w); + + void remove_widget(unsigned r, unsigned c); + + void remove_widget(std::shared_ptr<widget> w); + + mlk::size size(window& win) const noexcept override; + + void draw(window& win, const rectangle& dst) override; +}; + +} // !mlk + +#endif // !MALIKANIA_CLIENT_GRID_LAYOUT_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/key.hpp Thu Dec 15 13:46:46 2016 +0100 @@ -0,0 +1,244 @@ +/* + * key.hpp -- key definitions + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_KEY_HPP +#define MALIKANIA_CLIENT_KEY_HPP + +namespace mlk { + +/** + * \brief Describe keyboard modifiers + * + * This enumeration is a satisfied the Bitmask concept. + */ +enum class mod { + none = 0, //!< no modifiers + left_control = (1 << 1), //!< left control + left_alt = (1 << 2), //!< left alt + left_shift = (1 << 3), //!< left shift + left_super = (1 << 4), //!< left logo + right_control = (1 << 5), //!< right control + right_alt = (1 << 6), //!< right alt + right_shift = (1 << 7), //!< right shift + right_super = (1 << 8), //!< right logo + num_lock = (1 << 9), //!< num lock is on + caps_lock = (1 << 10), //!< caps lock is on + control = left_control | //!< left or right control + right_control, + shift = left_shift | //!< left or right shift + right_shift, + alt = left_alt | //!< left or right alt + right_alt, + super = left_super | //!< left or right super + right_super +}; + +/** + * \cond ENUM_HIDDEN_SYMBOLS + */ + +inline mod operator^(mod v1, mod v2) noexcept +{ + return static_cast<mod>(static_cast<unsigned>(v1) ^ static_cast<unsigned>(v2)); +} + +inline mod operator&(mod v1, mod v2) noexcept +{ + return static_cast<mod>(static_cast<unsigned>(v1)& static_cast<unsigned>(v2)); +} + +inline mod operator|(mod v1, mod v2) noexcept +{ + return static_cast<mod>(static_cast<unsigned>(v1) | static_cast<unsigned>(v2)); +} + +inline mod operator~(mod v) noexcept +{ + return static_cast<mod>(~static_cast<unsigned>(v)); +} + +inline mod& operator|=(mod& v1, mod v2) noexcept +{ + v1 = static_cast<mod>(static_cast<unsigned>(v1) | static_cast<unsigned>(v2)); + + return v1; +} + +inline mod& operator&=(mod& v1, mod v2) noexcept +{ + v1 = static_cast<mod>(static_cast<unsigned>(v1)& static_cast<unsigned>(v2)); + + return v1; +} + +inline mod& operator^=(mod& v1, mod v2) noexcept +{ + v1 = static_cast<mod>(static_cast<unsigned>(v1) ^ static_cast<unsigned>(v2)); + + return v1; +} + +/** + * \endcond + */ + +/** + * \brief Key description. + */ +enum class key { + unknown, + a, + b, + c, + d, + e, + f, + g, + h, + i, + j, + k, + l, + m, + n, + o, + p, + q, + r, + s, + t, + u, + v, + w, + x, + y, + z, + exclaim, + double_quote, + percent, + dollar, + ampersand, + left_parenthese, + right_parenthese, + asterisk, + plus, + colon, + less, + greater, + question, + at, + caret, + underscore, + back_quote, + quote, + one, + two, + three, + four, + five, + six, + seven, + eight, + nine, + zero, + enter, + escape, + backspace, + tab, + space, + minus, + equals, + left_bracket, + right_bracket, + backslash, + hash, + semicolon, + apostrophe, + grave, + comma, + period, + slash, + caps_lock, + f1, + f2, + f3, + f4, + f5, + f6, + f7, + f8, + f9, + f10, + f11, + f12, + f13, + f14, + f15, + f16, + f17, + f18, + f19, + f20, + f21, + f22, + f23, + f24, + print_screen, + scroll_lock, + pause, + insert, + home, + page_up, + page_down, + del, + end, + right, + left, + down, + up, + kp_divide, + kp_multiply, + kp_minus, + kp_plus, + kp_enter, + kp_one, + kp_two, + kp_three, + kp_four, + kp_five, + kp_six, + kp_seven, + kp_eight, + kp_nine, + kp_zero, + mute, + volume_up, + volume_down, + left_control, + left_alt, + left_shift, + left_super, + right_control, + right_alt, + right_shift, + right_super +}; + +} // !mlk + +#endif // !MALIKANIA_CLIENT_KEY_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/layout.hpp Thu Dec 15 13:46:46 2016 +0100 @@ -0,0 +1,77 @@ +/* + * layout.hpp -- generic layout manager inside a frame + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_LAYOUT_HPP +#define MALIKANIA_CLIENT_LAYOUT_HPP + +/** + * \brief Generic layout manager inside a frame. + */ + +namespace mlk { + +class mouse_click_event; +class rectangle; +class size; +class window; + +/** + * \brief Manages the widgets inside a frame. + * + * Layouts are responsible of positioning the widgets inside a frame. They + * handle their positions and dispatch events if applicable. + * + * \see grid_layout + */ +class layout { +public: + /** + * Virtual destructor defaulted. + */ + virtual ~layout() noexcept = default; + + /** + * Handle mouse down. + * + * \param ev the mouse event + */ + virtual void handle_mouse_down(const mouse_click_event& ev) = 0; + + /** + * Handle mouse up. + * + * \param ev the event + */ + virtual void handle_mouse_up(const mouse_click_event& ev) = 0; + + /** + * Return the required minimum size to draw the whole layout. + */ + virtual mlk::size size(window& win) const = 0; + + /** + * Draw the layout content at the given position. + * + * \param win the window + */ + virtual void draw(window& win, const rectangle& dst) = 0; +}; + +} // !mlk + +#endif // !MALIKANIA_CLIENT_LAYOUT_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/mouse.hpp Thu Dec 15 13:46:46 2016 +0100 @@ -0,0 +1,41 @@ +/* + * mouse.hpp -- mouse definitions + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_MOUSE_HPP +#define MALIKANIA_CLIENT_MOUSE_HPP + +/** + * \file mouse.hpp + * \brief Mouse definitions. + */ + +namespace mlk { + +/** + * \brief Describe mouse button + */ +enum class mouse { + none, //!< no buttons are pressed + left, //!< left click is pressed + right, //!< right click is pressed + middle //!< middle click is pressed +}; + +} // !mlk + +#endif // !MALIKANIA_CLIENT_MOUSE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/theme.cpp Thu Dec 15 13:46:46 2016 +0100 @@ -0,0 +1,104 @@ +/* + * theme.cpp -- theming support for gui elements + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "button.hpp" +#include "color.hpp" +#include "frame.hpp" +#include "layout.hpp" +#include "point.hpp" +#include "rectangle.hpp" +#include "theme.hpp" +#include "window.hpp" + +namespace mlk { + +namespace { + +#include <dejavu_sans.cpp> + +} // !namespace + +theme::theme() + : m_font(std::string(dejavu_sans, sizeof (dejavu_sans)), 10) + , m_background_color(228, 228, 228, 255) + , m_border_color(102, 102, 102, 255) + , m_text_color(50, 50, 50, 255) + , m_frame_padding(10, 10) +{ +} + +size theme::size_button(const button &b) +{ + auto clip = m_font.clip(b.text()); + + return { + clip.width() + 12, + clip.height() + 12 + }; +} + +void theme::draw_frame(window& win, const frame &f) +{ + auto layout_size = f.layout()->size(win); + auto frame_pos = f.position(); + + // Frame border. + win.set_drawing_color(m_border_color); + win.draw_rectangle({ + frame_pos.x(), + frame_pos.y(), + layout_size.width() + m_frame_padding.width() * 2 + 2, + layout_size.height() + m_frame_padding.height() * 2 + 2 + }); + + // Frame content. + win.set_drawing_color(m_background_color); + win.fill_rectangle({ + frame_pos.x() + 1, + frame_pos.y() + 1, + layout_size.width() + m_frame_padding.width() * 2, + layout_size.height() + m_frame_padding.height() * 2 + }); + + // Layout. + f.layout()->draw(win, mlk::rectangle( + frame_pos.x() + m_frame_padding.width() + 1, + frame_pos.y() + m_frame_padding.height() + 1, + layout_size.width(), + layout_size.height() + )); +} + +void theme::draw_button(window& w, const button& b, const rectangle& rect) +{ + auto size = size_button(b); + + // Border. + w.set_drawing_color(m_border_color); + w.draw_rectangle({rect.x(), rect.y(), size.width(), size.height()}); + + // Box content. + w.set_drawing_color(m_background_color); + w.fill_rectangle({rect.x() + 1, rect.y() + 1, size.width() - 2, size.height() - 2}); + + // Text. + w.set_drawing_color(m_text_color); + w.draw_text(b.text(), m_font, point{rect.x() + 5, rect.y() + 5}); +} + +} // !mlk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/theme.hpp Thu Dec 15 13:46:46 2016 +0100 @@ -0,0 +1,103 @@ +/* + * theme.hpp -- theming support for gui elements + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_THEME_HPP +#define MALIKANIA_CLIENT_THEME_HPP + +/** + * \file theme.hpp + * \brief Theming support for gui elements. + */ + +#include "color.hpp" +#include "font.hpp" +#include "size.hpp" + +namespace mlk { + +class button; +class frame; +class rectangle; +class point; +class window; + +/** + * \brief Reimplement this class to provide your own theme. + */ +class theme { +private: + font m_font; + color m_background_color; + color m_border_color; + color m_text_color; + size m_frame_padding; + +public: + /** + * Default constructor. + */ + theme(); + + /** + * Virtual destructor defaulted. + */ + virtual ~theme() noexcept = default; + + inline const color& background_color() const noexcept + { + return m_background_color; + } + + inline const color& border_color() const noexcept + { + return m_border_color; + } + + inline const color& text_color() const noexcept + { + return m_text_color; + } + + /** + * Get the required bounding rectangle size for this button. + * + * \param b the button + * \return the size + */ + virtual size size_button(const button& b); + + /** + * Draw the frame. + * + * \param w the main window + * \param f the frame + */ + virtual void draw_frame(window& w, const frame& f); + + /** + * Draw a button. + * + * \param w the main window + * \param b the button + */ + virtual void draw_button(window& w, const button& b, const rectangle& rect); +}; + +} // !mlk + +#endif // !MALIKANIA_CLIENT_THEME_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/unique_layout.cpp Thu Dec 15 13:46:46 2016 +0100 @@ -0,0 +1,58 @@ +/* + * unique_layout.cpp -- basic layout with one widget + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "size.hpp" +#include "unique_layout.hpp" +#include "widget.hpp" + +namespace mlk { + +unique_layout::unique_layout(std::shared_ptr<mlk::widget> widget) noexcept + : m_widget(std::move(widget)) +{ +} + +void unique_layout::handle_mouse_down(const mouse_click_event& ev) +{ + if (m_widget) { + m_widget->handle_mouse_down(ev); + } +} + +void unique_layout::handle_mouse_up(const mouse_click_event& ev) +{ + if (m_widget) { + m_widget->handle_mouse_up(ev); + } +} + +mlk::size unique_layout::size(window& win) const +{ + if (m_widget) { + return m_widget->size(win); + } +} + +void unique_layout::draw(window& win, const rectangle& dst) +{ + if (m_widget) { + m_widget->draw(win, dst); + } +} + +} // !mlk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/unique_layout.hpp Thu Dec 15 13:46:46 2016 +0100 @@ -0,0 +1,103 @@ +/* + * unique_layout.hpp -- basic layout with one widget + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_UNIQUE_LAYOUT_HPP +#define MALIKANIA_CLIENT_UNIQUE_LAYOUT_HPP + +/** + * \file unique_layout.hpp + * \brief Basic layout with one widget. + */ + +#include <memory> + +#include "layout.hpp" + +namespace mlk { + +class widget; + +/** + * \brief Simple layout that consists of one widget. + */ +class unique_layout : public layout { +private: + std::shared_ptr<mlk::widget> m_widget; + +public: + /** + * Constructor with optional widget. + * + * \param widget the widget + */ + unique_layout(std::shared_ptr<mlk::widget> w = nullptr) noexcept; + + /** + * Get the handled widget. + * + * \return the widget + */ + inline const std::shared_ptr<mlk::widget>& widget() const noexcept + { + return m_widget; + } + + /** + * Overloaded function. + * + * \return the widget + */ + inline std::shared_ptr<mlk::widget>& widget() noexcept + { + return m_widget; + } + + /** + * Replace the current widget with this one. + * + * \param widget the widget + */ + inline void set_widget(std::shared_ptr<mlk::widget> widget) noexcept + { + m_widget = std::move(widget); + } + + /** + * \copydoc layout::handle_mouse_down + */ + void handle_mouse_down(const mouse_click_event& ev) override; + + /** + * \copydoc layout::handle_mouse_up + */ + void handle_mouse_up(const mouse_click_event& ev) override; + + /** + * \copydoc layout::size + */ + mlk::size size(window& win) const override; + + /** + * \copydoc layout::draw + */ + void draw(window& win, const rectangle& dst) override; +}; + +} // !mlk + +#endif // !MALIKANIA_CLIENT_UNIQUE_LAYOUT_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/widget.cpp Thu Dec 15 13:46:46 2016 +0100 @@ -0,0 +1,53 @@ +/* + * widget.cpp -- basic abstract widget for GUI + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "point.hpp" +#include "rectangle.hpp" +#include "size.hpp" +#include "widget.hpp" + +namespace mlk { + +void widget::handle_key_down(const key_event&) +{ +} + +void widget::handle_key_up(const key_event&) +{ +} + +void widget::handle_mouse_down(const mouse_click_event&) +{ +} + +void widget::handle_mouse_up(const mouse_click_event&) +{ +} + +void widget::draw(window& w, const point& pos) +{ + mlk::size sz = size(w); + mlk::rectangle rect{ + pos.x(), pos.y(), + sz.width(), sz.height() + }; + + draw(w, rect); +} + +} // !mlk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/widget.hpp Thu Dec 15 13:46:46 2016 +0100 @@ -0,0 +1,103 @@ +/* + * widget.hpp -- basic abstract widget for GUI + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_WIDGET_HPP +#define MALIKANIA_CLIENT_WIDGET_HPP + +/** + * \file widget.hpp + * \brief Basic abstract widget for GUI + */ + +namespace mlk { + +class key_event; +class mouse_click_event; +class point; +class rectangle; +class size; +class window; + +/** + * \brief Abstract widget + */ +class widget { +public: + /** + * Default destructor. + */ + virtual ~widget() noexcept = default; + + /** + * Handle a key down. + * + * \param ev the event + */ + virtual void handle_key_down(const key_event& ev); + + /** + * Handle a key up. + * + * \param ev the event + */ + virtual void handle_key_up(const key_event& ev); + + /** + * Handle mouse down event. + * + * \param ev the event + */ + virtual void handle_mouse_down(const mouse_click_event& ev); + + /** + * Handle a mouse up event. + * + * \param ev the event + */ + virtual void handle_mouse_up(const mouse_click_event& ev); + + /** + * Draw the widget at the specified position. + * + * Basic GUI elements will use the window theme to render themselves. + * + * \param w the window + */ + virtual void draw(window& w, const rectangle& rect) = 0; + + /** + * Helper to draw the whole widget at the given position. + * + * Effectively call draw with a rectangle overload. + * + * \param w the window + * \param pos the position + */ + virtual void draw(window& w, const point& pos); + + /** + * Get the required size to draw that widget. + * + * \return the widget size + */ + virtual mlk::size size(window& w) const noexcept = 0; +}; + +} // !mlk + +#endif // !MALIKANIA_CLIENT_WIDGET_HPP
--- a/libclient/malikania/window.cpp Thu Dec 15 13:43:09 2016 +0100 +++ b/libclient/malikania/window.cpp Thu Dec 15 13:46:46 2016 +0100 @@ -16,15 +16,33 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <iostream> #include <stdexcept> #include "color.hpp" +#include "frame.hpp" +#include "layout.hpp" +#include "theme.hpp" +#include "widget.hpp" #include "window_backend.hpp" namespace mlk { +bool window::is_frame_bound(frame& f, const point& ev_pos) noexcept +{ + auto frame_size = f.size(*this); + auto frame_padding = f.padding(); + auto frame_pos = f.position(); + + return ev_pos.x() >= frame_pos.x() + static_cast<int>(frame_padding.width()) && + ev_pos.y() >= frame_pos.y() + static_cast<int>(frame_padding.height()) && + ev_pos.x() <= frame_pos.x() + static_cast<int>(frame_padding.width() + frame_size.width()) && + ev_pos.y() <= frame_pos.y() + static_cast<int>(frame_padding.height() + frame_size.height()); +} + window::window(unsigned width, unsigned height, const std::string& title) : m_backend(std::make_unique<backend_impl>(*this, width, height, title)) + , m_theme(std::make_unique<mlk::theme>()) { } @@ -32,11 +50,6 @@ window::~window() noexcept = default; -void window::poll() -{ - m_backend->poll(*this); -} - void window::clear() { m_backend->clear(); @@ -93,6 +106,13 @@ m_backend->draw_rectangles(rectangles); } +void window::draw_frames() +{ + for (const auto& f : m_frames) { + f->draw(*this); + } +} + void window::fill_rectangle(const rectangle& rectangle) { m_backend->fill_rectangle(rectangle); @@ -113,6 +133,44 @@ m_backend->draw_text(text, font, point); } +void window::poll() +{ + m_backend->poll(*this); +} + +void window::handle_key_down(const key_event& ev) +{ +} + +void window::handle_key_up(const key_event&) +{ +} + +void window::handle_mouse_down(const mouse_click_event& ev) +{ + for (const auto& f : m_frames) { + if (is_frame_bound(*f, ev.pos)) { + f->layout()->handle_mouse_down({ + ev.button, + point(ev.pos.x() - f->position().x(), ev.pos.y() - f->position().y()) + }); + } + } +} + +void window::handle_mouse_up(const mouse_click_event& ev) +{ +} + +void window::handle_mouse_wheel(const mouse_wheel_event &ev) +{ +} + +void window::handle_quit() +{ + m_is_open = false; +} + window& window::operator=(window&&) noexcept = default; } // !mlk
--- a/libclient/malikania/window.hpp Thu Dec 15 13:43:09 2016 +0100 +++ b/libclient/malikania/window.hpp Thu Dec 15 13:46:46 2016 +0100 @@ -28,14 +28,55 @@ #include <memory> #include <vector> #include <string> +#include <unordered_set> + +#include "key.hpp" +#include "mouse.hpp" +#include "point.hpp" namespace mlk { class color; +class frame; class line; class font; -class point; class rectangle; +class theme; + +/** + * \brief Describe key event. + */ +class key_event { +public: + mlk::key key{key::unknown}; //!< layout-dependant key + mlk::key scancode{key::unknown}; //!< physical key + mlk::mod modifiers{mod::none}; //!< optional modifiers +}; + +/** + * \brief Describe mouse click event. + */ +class mouse_click_event { +public: + mouse button{mouse::none}; //!< which mouse button + point pos; //!< current mouse position +}; + +/** + * \brief Describe a mouse motion event. + */ +class mouse_motion_event { +public: + point pos; //!< current mouse position +}; + +/** + * \brief Describe mouse wheel (up/down) event. + */ +class mouse_wheel_event { +public: + point pos; //!< current mouse position +}; /** * \brief Main window class and drawing. @@ -45,9 +86,13 @@ class backend_impl; std::unique_ptr<backend_impl> m_backend; + std::unique_ptr<mlk::theme> m_theme; + std::unordered_set<std::shared_ptr<frame>> m_frames; bool m_is_open{true}; + bool is_frame_bound(frame&, const point&) noexcept; + public: /** * Create a window. @@ -57,7 +102,9 @@ * \param title the optional title * \throw std::runtime_error on errors */ - window(unsigned width = 640, unsigned height = 480, const std::string& title = "Malikania Engine"); + window(unsigned width = 640, + unsigned height = 480, + const std::string& title = "Malikania Engine"); /** * Move constructor defaulted. @@ -99,10 +146,35 @@ return *m_backend; } + void add_frame(std::shared_ptr<mlk::frame> frame) + { + m_frames.insert(std::move(frame)); + } + + void remove_frame(std::shared_ptr<mlk::frame> frame) + { + m_frames.erase(frame); + } + /** - * Poll pending events. + * Get the current theme. + * + * \return the theme */ - void poll(); + inline const mlk::theme& theme() const noexcept + { + return *m_theme; + } + + /** + * Overloaded function. + * + * \return the theme + */ + inline mlk::theme& theme() noexcept + { + return *m_theme; + } /** * Clear the window content with the current drawing color. @@ -178,6 +250,11 @@ void draw_rectangles(const std::vector<rectangle>& rects); /** + * Draw internal GUI frames. + */ + void draw_frames(); + + /** * Fill the given rectangle with the current color. * * \param rect the rectangle @@ -216,6 +293,51 @@ void draw_text(const std::string& text, font& font, const point& point); /** + * Poll all pending events and call appropriate functions. + */ + void poll(); + + /** + * Key down event. + * + * \param ev the event + */ + virtual void handle_key_down(const key_event& ev); + + /** + * Key released event. + * + * \param ev the event + */ + virtual void handle_key_up(const key_event& ev); + + /** + * Mouse click event. + * + * \param ev the event + */ + virtual void handle_mouse_down(const mouse_click_event& ev); + + /** + * Mouse click release event. + * + * \param ev the event + */ + virtual void handle_mouse_up(const mouse_click_event& ev); + + /** + * Mouse wheel event. + * + * \param ev the event + */ + virtual void handle_mouse_wheel(const mouse_wheel_event& ev); + + /** + * Quit request. + */ + virtual void handle_quit(); + + /** * Move assigment operator defaulted. * * \return this