changeset 212:e50f51702df4

client: add basic button prototype, closes #908 @1h
author David Demelier <markand@malikania.fr>
date Fri, 04 Jan 2019 18:26:04 +0100
parents ac99f440ee44
children 61580ff3138a
files libmlk-client-js/malikania/client/js/event_js_api.cpp libmlk-client/malikania/client/button.cpp libmlk-client/malikania/client/button.hpp libmlk-client/malikania/client/event.hpp libmlk-client/malikania/client/widget.cpp libmlk-client/malikania/client/widget.hpp mlk-client/main.cpp
diffstat 7 files changed, 193 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/libmlk-client-js/malikania/client/js/event_js_api.cpp	Fri Jan 04 17:00:04 2019 +0100
+++ b/libmlk-client-js/malikania/client/js/event_js_api.cpp	Fri Jan 04 18:26:04 2019 +0100
@@ -20,6 +20,8 @@
 
 #include "event_js_api.hpp"
 
+namespace duk = mlk::js::duk;
+
 namespace mlk::client::js {
 
 namespace {
@@ -31,6 +33,7 @@
 	mouse_wheel_event,
 	text_event,
 	quit_event,
+	message_event,
 };
 
 const duk_number_list_entry codes[] = {
@@ -40,6 +43,7 @@
 	{ "MOUSE_WHEEL",        static_cast<int>(type::mouse_wheel_event)       },
 	{ "TEXT",               static_cast<int>(type::text_event)              },
 	{ "QUIT",               static_cast<int>(type::quit_event)              },
+	{ "MESSAGE",            static_cast<int>(type::message_event)           },
 	{ nullptr,              -1                                              }
 };
 
@@ -92,6 +96,28 @@
 		duk_push_int(ctx, static_cast<int>(type::text_event));
 		duk_put_prop_string(ctx, -2, "type");
 	}
+
+	void operator()(const message_event& ev)
+	{
+		duk::stack_guard sa(ctx);
+
+		// TODO: create appropriate recursive function instead.
+		duk_push_int(ctx, static_cast<int>(type::message_event));
+		duk_put_prop_string(ctx, -2, "type");
+
+		if (ev.code) {
+			duk_push_int(ctx, ev.code.value());
+			duk_put_prop_string(ctx, -2, "code");
+			duk_push_string(ctx, ev.code.category().name());
+			duk_put_prop_string(ctx, -2, "category");
+		}
+
+		if (ev.message.is_object()) {
+			duk::push(ctx, ev.message.dump(0));
+			duk_json_decode(ctx, -1);
+			duk_put_prop_string(ctx, -2, "message");
+		}
+	}
 };
 
 } // !namespace
--- a/libmlk-client/malikania/client/button.cpp	Fri Jan 04 17:00:04 2019 +0100
+++ b/libmlk-client/malikania/client/button.cpp	Fri Jan 04 18:26:04 2019 +0100
@@ -39,11 +39,16 @@
 	text_ = std::move(text);
 }
 
+void button::set_on_press(on_press_func func) noexcept
+{
+	on_press_ = std::move(func);
+}
+
 void button::handle_event(const event& ev)
 {
 	const auto mev = std::get_if<mouse_click_event>(&ev);
 
-	if (!mev)
+	if (!mev || !is_bound(mev->position))
 		return;
 
 	if (mev->button == mouse::left) {
@@ -56,24 +61,25 @@
 
 void button::draw(painter& p)
 {
-	const auto& font = get_theme().get_font();
+	auto& font = get_theme().get_font();
+
+	const auto position = get_position();
+	const auto size = get_size();
 	const auto textsize = font.clip(text_);
 
 	p.set_drawing_color({128, 68, 21});
-	p.draw_rectangle({position_.x - 3, position_.y - 3, size_.width + 6, size_.height + 6});
+	p.draw_rectangle({position.x - 3, position.y - 3, size.width + 6, size.height + 6});
 	p.set_drawing_color({85, 38, 0});
-	p.draw_rectangle({position_.x - 2, position_.y - 2, size_.width + 4, size_.height + 4});
+	p.draw_rectangle({position.x - 2, position.y - 2, size.width + 4, size.height + 4});
 	p.set_drawing_color({128, 68, 21});
-	p.draw_rectangle({position_.x - 1, position_.y - 1, size_.width + 2, size_.height + 2});
+	p.draw_rectangle({position.x - 1, position.y - 1, size.width + 2, size.height + 2});
 	p.set_drawing_color({255, 208, 170});
-	p.fill_rectangle({position_.x, position_.y, size_.width, size_.height});
+	p.fill_rectangle({position.x, position.y, size.width, size.height});
 	p.set_drawing_color(color::from_name("black"));
-#if 0
-	p.draw_text(text_, font, point{
-		position_.x + (static_cast<int>(size_.width) / 2) - (static_cast<int>(textsize.width) / 2),
-		position_.y + (static_cast<int>(size_.height) / 2) - (static_cast<int>(textsize.height) / 2)
+	font.draw(p, text_, point{
+		position.x + (static_cast<int>(size.width) / 2) - (static_cast<int>(textsize.width) / 2),
+		position.y + (static_cast<int>(size.height) / 2) - (static_cast<int>(textsize.height) / 2)
 	});
-#endif
 }
 
 } // !mlk::client
--- a/libmlk-client/malikania/client/button.hpp	Fri Jan 04 17:00:04 2019 +0100
+++ b/libmlk-client/malikania/client/button.hpp	Fri Jan 04 18:26:04 2019 +0100
@@ -69,16 +69,18 @@
 	void set_text(std::string text) noexcept;
 
 	/**
+	 * Set the press handler.
+	 *
+	 * \param func the function
+	 */
+	void set_on_press(on_press_func func) noexcept;
+
+	/**
 	 * \copydoc widget::handle_event
 	 */
 	void handle_event(const event& ev);
 
 	/**
-	 * Bring back other functions.
-	 */
-	using widget::draw;
-
-	/**
 	 * \copydoc widget::draw
 	 */
 	void draw(painter& painter) override;
--- a/libmlk-client/malikania/client/event.hpp	Fri Jan 04 17:00:04 2019 +0100
+++ b/libmlk-client/malikania/client/event.hpp	Fri Jan 04 18:26:04 2019 +0100
@@ -29,6 +29,8 @@
 
 #include <malikania/point.hpp>
 
+#include <json.hpp>
+
 #include "mouse.hpp"
 #include "key.hpp"
 
@@ -50,21 +52,21 @@
 struct mouse_click_event {
 	bool pressed{true};             //!< is pressed?
 	mouse button{mouse::none};      //!< which mouse button
-	point pos;                      //!< current mouse position
+	point position;                 //!< current mouse position
 };
 
 /**
  * \brief Describe a mouse motion event.
  */
 struct mouse_motion_event {
-	point pos;                      //!< current mouse position
+	point position;                 //!< current mouse position
 };
 
 /**
  * \brief Describe mouse wheel (up/down) event.
  */
 struct mouse_wheel_event {
-	point pos;                      //!< current mouse position
+	point position;                 //!< current mouse position
 };
 
 /**
@@ -81,6 +83,14 @@
 };
 
 /**
+ * \brief Network message event.
+ */
+struct message_event {
+	std::error_code code;
+	nlohmann::json message;
+};
+
+/**
  * \brief Variant with all possible events.
  */
 using variant = std::variant<
@@ -90,7 +100,8 @@
 	mouse_click_event,
 	mouse_motion_event,
 	mouse_wheel_event,
-	text_event
+	text_event,
+	message_event
 >;
 
 /**
--- a/libmlk-client/malikania/client/widget.cpp	Fri Jan 04 17:00:04 2019 +0100
+++ b/libmlk-client/malikania/client/widget.cpp	Fri Jan 04 18:26:04 2019 +0100
@@ -61,4 +61,37 @@
 	theme_ = std::addressof(theme);
 }
 
+auto widget::get_state() const noexcept -> state
+{
+	return state_;
+}
+
+auto widget::is_bound(const point& position) const noexcept -> bool
+{
+	return position.x >= position_.x &&
+	       position.y >= position_.y &&
+	       position.x <= position_.x + size_.width &&
+	       position.y <= position_.y + size_.height;
+}
+
+void widget::focus() noexcept
+{
+	state_ = state::focused;
+}
+
+void widget::unfocus() noexcept
+{
+	state_ = state::normal;
+}
+
+void widget::hide() noexcept
+{
+	state_ = state::hidden;
+}
+
+void widget::show() noexcept
+{
+	state_ = state::normal;
+}
+
 } // !mlk::client
--- a/libmlk-client/malikania/client/widget.hpp	Fri Jan 04 17:00:04 2019 +0100
+++ b/libmlk-client/malikania/client/widget.hpp	Fri Jan 04 18:26:04 2019 +0100
@@ -38,10 +38,18 @@
  * \brief Abstract widget
  */
 class widget {
-protected:
-	theme* theme_;                  //!< widget theme
-	point position_;                //!< widget position
-	size size_;                     //!< widget size
+public:
+	enum class state {
+		normal,         //!< widget is in normal state
+		hidden,         //!< widget is set hidden
+		focused,        //!< widget is focused
+	};
+
+private:
+	theme* theme_;
+	point position_;
+	size size_;
+	state state_{state::normal};
 
 public:
 	/**
@@ -109,6 +117,40 @@
 	void set_theme(theme& theme) noexcept;
 
 	/**
+	 * Get the widget state.
+	 *
+	 * \return the state
+	 */
+	auto get_state() const noexcept -> state;
+
+	/**
+	 * Check if the point is within the widget.
+	 *
+	 * \return true if the position is bound to the rectangle
+	 */
+	auto is_bound(const point& position) const noexcept -> bool;
+
+	/**
+	 * Change state to focus.
+	 */
+	virtual void focus() noexcept;
+
+	/**
+	 * Change state to normal.
+	 */
+	virtual void unfocus() noexcept;
+
+	/**
+	 * Change state to hidden.
+	 */
+	virtual void hide() noexcept;
+
+	/**
+	 * Change state to normal.
+	 */
+	virtual void show() noexcept;
+
+	/**
 	 * Draw the widget.
 	 *
 	 * \param painter the painter
--- a/mlk-client/main.cpp	Fri Jan 04 17:00:04 2019 +0100
+++ b/mlk-client/main.cpp	Fri Jan 04 18:26:04 2019 +0100
@@ -16,6 +16,51 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <chrono>
+#include <iostream>
+#include <thread>
+
+#include <malikania/client/color.hpp>
+#include <malikania/client/button.hpp>
+#include <malikania/client/window.hpp>
+#include <malikania/client/painter.hpp>
+
+using namespace std::chrono_literals;
+
+int main(int argc, char** argv)
+{
+	mlk::client::window win(1920/2, 1080/2);
+	mlk::client::painter painter(win);
+	mlk::client::button button("click me");
+
+	button.set_size({200, 64});
+	button.set_position({50, 50});
+	button.set_on_press([] {
+		std::cout << "je suis clické" << std::endl;
+	});
+
+	for (;;) {
+		while (auto ev = win.poll()) {
+			if (std::get_if<mlk::client::quit_event>(&ev))
+				goto end;
+			else
+				button.handle_event(ev);
+		}
+
+		painter.set_drawing_color(mlk::client::color::from_hex(0xffffffff));
+		painter.clear();
+		button.draw(painter);
+		painter.present();
+
+		std::this_thread::sleep_for(50ms);
+	}
+
+end:
+	return 0;
+}
+
+#if 0
+
 #include <cerrno>
 #include <cstring>
 #include <fstream>
@@ -24,6 +69,8 @@
 
 #include <malikania/client/js/context.hpp>
 
+// Simple javascript startup file. Don't delete.
+
 int main(int argc, char** argv)
 {
 	-- argc;
@@ -57,3 +104,5 @@
 
 	return 0;
 }
+
+#endif