view libmlk-client-js/malikania/client/js/painter_js_api.cpp @ 210:1599919b5de6

client: allow starting a Javascript file
author David Demelier <markand@malikania.fr>
date Fri, 07 Dec 2018 19:31:10 +0100
parents 263122adef77
children
line wrap: on
line source

/*
 * painter_js_api.cpp -- painter (JavaScript binding)
 *
 * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
 *
 * 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 <cassert>

#include <malikania/line.hpp>
#include <malikania/rectangle.hpp>
#include <malikania/point.hpp>

#include <malikania/client/color.hpp>
#include <malikania/client/painter.hpp>

#include <malikania/js/line_js_api.hpp>
#include <malikania/js/point_js_api.hpp>
#include <malikania/js/rectangle_js_api.hpp>

#include "color_js_api.hpp"
#include "font_js_api.hpp"
#include "painter_js_api.hpp"
#include "window_js_api.hpp"
#include "texture_js_api.hpp"

namespace mlk::client::js {

namespace {

const std::string_view signature("\xff""\xff""Malikania.Painter.self");
const std::string_view prototype("\xff""\xff""Malikania.Painter.prototype");

auto self(duk_context* ctx) -> painter&
{
        mlk::js::duk::stack_guard sa(ctx);

	duk_push_this(ctx);
	duk_get_prop_string(ctx, -1, signature.data());
	auto ptr = duk_to_pointer(ctx, -1);
	duk_pop_2(ctx);

	if (!ptr)
		duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an Painter object");

	return *static_cast<painter*>(ptr);
}

auto Painter_constructor(duk_context* ctx) -> duk_ret_t
{
        mlk::js::duk::stack_guard sa(ctx);

	if (!duk_is_constructor_call(ctx))
		duk_error(ctx, DUK_ERR_ERROR, "painter must be new-constructed");

	try {
		duk_push_this(ctx);

		if (duk_get_top(ctx) == 2)
			duk_push_pointer(ctx, new painter(mlk::js::duk::require<window>(ctx, 0)));
		else
			duk_push_pointer(ctx, new painter(
				mlk::js::duk::require<window>(ctx, 0),
				mlk::js::duk::require<texture>(ctx, 1)
			));

		duk_put_prop_string(ctx, -2, signature.data());
		duk_pop(ctx);
	} catch (const std::exception& ex) {
		duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what());
	}

	return 0;
}

auto Painter_prototype_clear(duk_context* ctx) -> duk_ret_t
{
	try {
		self(ctx).clear();
	} catch (const std::exception& ex) {
		duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what());
	}

	return 0;
}

auto Painter_prototype_use(duk_context* ctx) -> duk_ret_t
{
	try {
		if (auto* w = mlk::js::duk::get<window>(ctx, 0); w)
			self(ctx).use(*w);
		else if (auto* t = mlk::js::duk::get<texture>(ctx, 0); t)
			self(ctx).use(*t);
		else
			throw std::runtime_error("expected Window or Texture");
	} catch (const std::exception& ex) {
		duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what());
	}

	return 0;
}

auto Painter_prototype_present(duk_context* ctx) -> duk_ret_t
{
	try {
		self(ctx).present();
	} catch (const std::exception& ex) {
		duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what());
	}

	return 0;
}

auto Painter_prototype_drawingColor(duk_context* ctx) -> duk_ret_t
{
	try {
                mlk::js::duk::push(ctx, self(ctx).get_drawing_color());
	} catch (const std::exception& ex) {
		duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what());
	}

	return 1;
}

auto Painter_prototype_drawLine(duk_context* ctx) -> duk_ret_t
{
	try {
		self(ctx).draw_line(mlk::js::duk::get<line>(ctx, 0));
	} catch (const std::exception& ex) {
		duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what());
	}

	return 0;
}

auto Painter_prototype_drawPoint(duk_context* ctx) -> duk_ret_t
{
	try {
		self(ctx).draw_point(mlk::js::duk::get<point>(ctx, 0));
	} catch (const std::exception& ex) {
		duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what());
	}

	return 0;
}

auto Painter_prototype_drawRectangle(duk_context* ctx) -> duk_ret_t
{
	try {
		self(ctx).draw_rectangle(mlk::js::duk::get<rectangle>(ctx, 0));
	} catch (const std::exception& ex) {
		duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what());
	}

	return 0;
}

auto Painter_prototype_fillRectangle(duk_context* ctx) -> duk_ret_t
{
	try {
		self(ctx).fill_rectangle(mlk::js::duk::get<rectangle>(ctx, 0));
	} catch (const std::exception& ex) {
		duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what());
	}

	return 0;
}

auto Painter_prototype_setDrawingColor(duk_context* ctx) -> duk_ret_t
{
	try {
		self(ctx).set_drawing_color(mlk::js::duk::get<color>(ctx, 0));
	} catch (const std::exception& ex) {
		duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what());
	}

	return 0;
}

} // !namespace

const duk_function_list_entry methods[] = {
	{ "clear",              Painter_prototype_clear,                0 },
	{ "use",                Painter_prototype_use,                  1 },
	{ "drawingColor",       Painter_prototype_drawingColor,         0 },
	{ "drawLine",           Painter_prototype_drawLine,             1 },
	{ "drawPoint",          Painter_prototype_drawPoint,            1 },
	{ "drawRectangle",      Painter_prototype_drawRectangle,        1 },
	{ "fillRectangle",      Painter_prototype_fillRectangle,        1 },
	{ "present",            Painter_prototype_present,              0 },
	{ "setDrawingColor",    Painter_prototype_setDrawingColor,      1 },
	{ nullptr,              nullptr,                                0 }
};

void load_painter_api(duk_context* ctx)
{
        mlk::js::duk::stack_guard sa(ctx);

	duk_get_global_string(ctx, "Malikania");
	duk_push_c_function(ctx, Painter_constructor, DUK_VARARGS);
	duk_push_object(ctx);
	duk_put_function_list(ctx, -1, methods);
	duk_put_prop_string(ctx, -2, "prototype");
	duk_put_prop_string(ctx, -2, "Painter");
	duk_pop(ctx);
}

} // !mlk::client::js

namespace mlk::js::duk {

auto type_traits<mlk::client::painter>::require(duk_context* ctx, duk_idx_t index) -> mlk::client::painter&
{
	assert(ctx);

        mlk::js::duk::stack_guard sa(ctx);

	duk_get_prop_string(ctx, index, mlk::client::js::signature.data());
	auto ptr = duk_to_pointer(ctx, -1);
	duk_pop(ctx);

	if (!ptr)
		duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Painter object");

	return *static_cast<mlk::client::painter*>(ptr);
}

} // !mlk::js::duk