#include "StarWidgetLuaBindings.hpp" #include "StarJsonExtra.hpp" #include "StarLuaGameConverters.hpp" #include "StarGuiReader.hpp" #include "StarCanvasWidget.hpp" #include "StarLabelWidget.hpp" #include "StarListWidget.hpp" #include "StarButtonWidget.hpp" #include "StarButtonGroup.hpp" #include "StarTextBoxWidget.hpp" #include "StarProgressWidget.hpp" #include "StarSliderBar.hpp" #include "StarItemGridWidget.hpp" #include "StarItemSlotWidget.hpp" #include "StarItemDatabase.hpp" #include "StarFlowLayout.hpp" namespace Star { LuaMethods LuaUserDataMethods::make() { LuaMethods methods; methods.registerMethodWithSignature("size", mem_fn(&CanvasWidget::size)); methods.registerMethodWithSignature("mousePosition", mem_fn(&CanvasWidget::mousePosition)); methods.registerMethodWithSignature("clear", mem_fn(&CanvasWidget::clear)); methods.registerMethod("drawDrawable", [](CanvasWidgetPtr canvasWidget, Drawable drawable, Maybe screenPos) { canvasWidget->drawDrawable(std::move(drawable), screenPos.value(Vec2F())); }); methods.registerMethod("drawDrawables", [](CanvasWidgetPtr canvasWidget, List drawables, Maybe screenPos) { Vec2F pos = screenPos.value(Vec2F()); for (auto& drawable : drawables) canvasWidget->drawDrawable(std::move(drawable), pos); }); methods.registerMethod("drawImage", [](CanvasWidgetPtr canvasWidget, String image, Vec2F position, Maybe scale, Maybe color, Maybe centered) { if (centered && *centered) canvasWidget->drawImageCentered(image, position, scale.value(1.0f), color.value(Color::White).toRgba()); else canvasWidget->drawImage(image, position, scale.value(1.0f), color.value(Color::White).toRgba()); }); methods.registerMethod("drawImageDrawable", [](CanvasWidgetPtr canvasWidget, String image, Vec2F position, MVariant scale, Maybe color, Maybe rotation) { auto drawable = Drawable::makeImage(image, 1.0, true, {0.0, 0.0}, color.value(Color::White)); if (auto s = scale.maybe()) drawable.transform(Mat3F::scaling(*s)); else if(auto s = scale.maybe()) drawable.transform(Mat3F::scaling(*s)); if (rotation) drawable.rotate(*rotation); canvasWidget->drawDrawable(drawable, position); }); methods.registerMethod("drawImageRect", [](CanvasWidgetPtr canvasWidget, String image, RectF texCoords, RectF screenCoords, Maybe color) { canvasWidget->drawImageRect(image, texCoords, screenCoords, color.value(Color::White).toRgba()); }); methods.registerMethod("drawTiledImage", [](CanvasWidgetPtr canvasWidget, String image, Vec2D offset, RectF screenCoords, Maybe scale, Maybe color) { canvasWidget->drawTiledImage(image, scale.value(1.0f), offset, screenCoords, color.value(Color::White).toRgba()); }); methods.registerMethod("drawLine", [](CanvasWidgetPtr canvasWidget, Vec2F begin, Vec2F end, Maybe color, Maybe lineWidth) { canvasWidget->drawLine(begin, end, color.value(Color::White).toRgba(), lineWidth.value(1.0f)); }); methods.registerMethod("drawRect", [](CanvasWidgetPtr canvasWidget, RectF rect, Maybe color) { canvasWidget->drawRect(rect, color.value(Color::White).toRgba()); }); methods.registerMethod("drawPoly", [](CanvasWidgetPtr canvasWidget, PolyF poly, Maybe color, Maybe lineWidth) { canvasWidget->drawPoly(poly, color.value(Color::White).toRgba(), lineWidth.value(1.0f)); }); methods.registerMethod("drawTriangles", [](CanvasWidgetPtr canvasWidget, List triangles, Maybe color) { auto tris = triangles.transformed([](PolyF const& poly) { if (poly.sides() != 3) throw StarException("Triangle must have exactly 3 sides"); return tuple(poly.vertex(0), poly.vertex(1), poly.vertex(2)); }); canvasWidget->drawTriangles(tris, color.value(Color::White).toRgba()); }); methods.registerMethod("drawText", [](CanvasWidgetPtr canvasWidget, String text, Json tp, unsigned fontSize, Maybe color, Maybe lineSpacing, Maybe font, Maybe directives) { canvasWidget->drawText(text, TextPositioning(tp), fontSize, color.value(Color::White).toRgba(), FontMode::Normal, lineSpacing.value(DefaultLineSpacing), font.value(""), directives.value("")); }); return methods; } LuaCallbacks LuaBindings::makeWidgetCallbacks(Widget* parentWidget, GuiReaderPtr reader) { if (!reader) reader = make_shared(); LuaCallbacks callbacks; // a bit miscellaneous, but put this here since widgets have access to gui context callbacks.registerCallback("playSound", [parentWidget](String const& audio, Maybe loops, Maybe volume) { parentWidget->context()->playAudio(audio, loops.value(0), volume.value(1.0f)); }); // widget userdata methods callbacks.registerCallback("bindCanvas", [parentWidget](String const& widgetName) -> Maybe { if (auto canvas = parentWidget->fetchChild(widgetName)) return canvas; return {}; }); // generic widget callbacks callbacks.registerCallback("getPosition", [parentWidget](String const& widgetName) -> Maybe { if (auto widget = parentWidget->fetchChild(widgetName)) return widget->relativePosition(); return {}; }); callbacks.registerCallback("setPosition", [parentWidget](String const& widgetName, Vec2I const& position) { if (auto widget = parentWidget->fetchChild(widgetName)) widget->setPosition(position); }); callbacks.registerCallback("getSize", [parentWidget](String const& widgetName) -> Maybe { if (auto widget = parentWidget->fetchChild(widgetName)) return widget->size(); return {}; }); callbacks.registerCallback("setSize", [parentWidget](String const& widgetName, Vec2I const& size) { if (auto widget = parentWidget->fetchChild(widgetName)) widget->setSize(size); }); callbacks.registerCallback("setVisible", [parentWidget](String const& widgetName, bool visible) { if (auto widget = parentWidget->fetchChild(widgetName)) widget->setVisibility(visible); }); callbacks.registerCallback("active", [parentWidget](String const& widgetName) -> Maybe { if (auto widget = parentWidget->fetchChild(widgetName)) return widget->active(); return {}; }); callbacks.registerCallback("focus", [parentWidget](String const& widgetName) { if (auto widget = parentWidget->fetchChild(widgetName)) widget->focus(); }); callbacks.registerCallback("hasFocus", [parentWidget](String const& widgetName) -> Maybe { if (auto widget = parentWidget->fetchChild(widgetName)) return widget->hasFocus(); return {}; }); callbacks.registerCallback("blur", [parentWidget](String const& widgetName) { if (auto widget = parentWidget->fetchChild(widgetName)) widget->blur(); }); callbacks.registerCallback("getData", [parentWidget](String const& widgetName) { if (auto widget = parentWidget->fetchChild(widgetName)) return widget->data(); return Json(); }); callbacks.registerCallback("setData", [parentWidget](String const& widgetName, Json const& data) { if (auto widget = parentWidget->fetchChild(widgetName)) widget->setData(data); }); callbacks.registerCallback("getChildAt", [parentWidget](Vec2I const& screenPosition) -> Maybe { if (auto widget = parentWidget->getChildAt(screenPosition)) return widget->fullName(); else return{}; }); callbacks.registerCallback("inMember", [parentWidget](String const& widgetName, Vec2I const& screenPosition) -> Maybe { if (auto widget = parentWidget->fetchChild(widgetName)) return widget->inMember(screenPosition); else return {}; }); callbacks.registerCallback("addChild", [parentWidget, reader](String const& widgetName, Json const& newChildConfig, Maybe const& newChildName) { if (auto widget = parentWidget->fetchChild(widgetName)) { String name = newChildName.value(toString(Random::randu64())); WidgetPtr newChild = reader->makeSingle(name, newChildConfig); widget->addChild(name, newChild); } }); callbacks.registerCallback("removeAllChildren", [parentWidget](String const& widgetName) { if (auto widget = parentWidget->fetchChild(widgetName)) widget->removeAllChildren(); }); callbacks.registerCallback("removeChild", [parentWidget](String const& widgetName, String const& childName) { if (auto widget = parentWidget->fetchChild(widgetName)) widget->removeChild(childName); }); // callbacks only valid for specific widget types callbacks.registerCallback("getText", [parentWidget](String const& widgetName) -> Maybe { if (auto widget = parentWidget->fetchChild(widgetName)) { if (auto label = as(widget)) return label->text(); else if (auto button = as(widget)) return button->getText(); else if (auto textBox = as(widget)) return textBox->getText(); } return {}; }); callbacks.registerCallback("setText", [parentWidget](String const& widgetName, String const& text) { if (auto widget = parentWidget->fetchChild(widgetName)) { if (auto label = as(widget)) label->setText(text); else if (auto button = as(widget)) button->setText(text); else if (auto textBox = as(widget)) textBox->setText(text); } }); callbacks.registerCallback("setFontColor", [parentWidget](String const& widgetName, Color const& color) { if (auto widget = parentWidget->fetchChild(widgetName)) { if (auto label = as(widget)) label->setColor(color); else if (auto button = as(widget)) button->setFontColor(color); else if (auto textBox = as(widget)) textBox->setColor(color); } }); callbacks.registerCallback("setImage", [parentWidget](String const& widgetName, String const& imagePath) { if (auto image = parentWidget->fetchChild(widgetName)) image->setImage(imagePath); }); callbacks.registerCallback("setImageScale", [parentWidget](String const& widgetName, float const& imageScale) { if (auto image = parentWidget->fetchChild(widgetName)) image->setScale(imageScale); }); callbacks.registerCallback("setImageRotation", [parentWidget](String const& widgetName, float const& imageRotation) { if (auto image = parentWidget->fetchChild(widgetName)) image->setRotation(imageRotation); }); callbacks.registerCallback("setButtonEnabled", [parentWidget](String const& widgetName, bool enabled) { if (auto button = parentWidget->fetchChild(widgetName)) button->setEnabled(enabled); }); callbacks.registerCallback("setButtonImage", [parentWidget](String const& widgetName, String const& baseImage) { if (auto button = parentWidget->fetchChild(widgetName)) button->setImages(baseImage); }); callbacks.registerCallback("setButtonImages", [parentWidget](String const& widgetName, Json const& imageSet) { if (auto button = parentWidget->fetchChild(widgetName)) button->setImages(imageSet.getString("base"), imageSet.getString("hover", ""), imageSet.getString("pressed", ""), imageSet.getString("disabled", "")); }); callbacks.registerCallback("setButtonCheckedImages", [parentWidget](String const& widgetName, Json const& imageSet) { if (auto button = parentWidget->fetchChild(widgetName)) button->setCheckedImages(imageSet.getString("base"), imageSet.getString("hover", ""), imageSet.getString("pressed", ""), imageSet.getString("disabled", "")); }); callbacks.registerCallback("setButtonOverlayImage", [parentWidget](String const& widgetName, String const& overlayImage) { if (auto button = parentWidget->fetchChild(widgetName)) button->setOverlayImage(overlayImage); }); callbacks.registerCallback("getChecked", [parentWidget](String const& widgetName) -> Maybe { if (auto button = parentWidget->fetchChild(widgetName)) return button->isChecked(); return {}; }); callbacks.registerCallback("setChecked", [parentWidget](String const& widgetName, bool checked) { if (auto button = parentWidget->fetchChild(widgetName)) button->setChecked(checked); }); callbacks.registerCallback("getSelectedOption", [parentWidget](String const& widgetName) -> Maybe { if (auto buttonGroup = parentWidget->fetchChild(widgetName)) return buttonGroup->checkedId(); return {}; }); callbacks.registerCallback("getSelectedData", [parentWidget](String const& widgetName) -> Json { if (auto buttonGroup = parentWidget->fetchChild(widgetName)) { if (auto button = buttonGroup->checkedButton()) return button->data(); } return {}; }); callbacks.registerCallback("setSelectedOption", [parentWidget](String const& widgetName, Maybe index) { if (auto buttonGroup = parentWidget->fetchChild(widgetName)) buttonGroup->select(index.value(ButtonGroup::NoButton)); }); callbacks.registerCallback("setOptionEnabled", [parentWidget](String const& widgetName, int index, bool enabled) { if (auto buttonGroup = parentWidget->fetchChild(widgetName)) { if (auto button = buttonGroup->button(index)) button->setEnabled(enabled); } }); callbacks.registerCallback("setOptionVisible", [parentWidget](String const& widgetName, int index, bool visible) { if (auto buttonGroup = parentWidget->fetchChild(widgetName)) { if (auto button = buttonGroup->button(index)) button->setVisibility(visible); } }); callbacks.registerCallback("setProgress", [parentWidget](String const& widgetName, float const& value) { if (auto progress = parentWidget->fetchChild(widgetName)) progress->setCurrentProgressLevel(value); }); callbacks.registerCallback("setSliderEnabled", [parentWidget](String const& widgetName, bool enabled) { if (auto slider = parentWidget->fetchChild(widgetName)) slider->setEnabled(enabled); }); callbacks.registerCallback("getSliderValue", [parentWidget](String const& widgetName) -> Maybe { if (auto slider = parentWidget->fetchChild(widgetName)) return slider->val(); return {}; }); callbacks.registerCallback("setSliderValue", [parentWidget](String const& widgetName, int newValue) { if (auto slider = parentWidget->fetchChild(widgetName)) return slider->setVal(newValue); }); callbacks.registerCallback("setSliderRange", [parentWidget](String const& widgetName, int newMin, int newMax, Maybe newDelta) { if (auto slider = parentWidget->fetchChild(widgetName)) return slider->setRange(newMin, newMax, newDelta.value(1)); }); callbacks.registerCallback("clearListItems", [parentWidget](String const& widgetName) { if (auto list = parentWidget->fetchChild(widgetName)) list->clear(); }); callbacks.registerCallback("addListItem", [parentWidget](String const& widgetName) -> Maybe { if (auto list = parentWidget->fetchChild(widgetName)) { auto newItem = list->addItem(); return newItem->name(); } return {}; }); callbacks.registerCallback("removeListItem", [parentWidget](String const& widgetName, size_t at) { if (auto list = parentWidget->fetchChild(widgetName)) list->removeItem(at); }); callbacks.registerCallback("getListSelected", [parentWidget](String const& widgetName) -> Maybe { if (auto list = parentWidget->fetchChild(widgetName)) if (list->selectedItem() != NPos) return list->selectedWidget()->name(); return {}; }); callbacks.registerCallback("setListSelected", [parentWidget](String const& widgetName, String const& selectedName) { if (auto list = parentWidget->fetchChild(widgetName)) if (auto selected = list->fetchChild(selectedName)) list->setSelectedWidget(selected); }); callbacks.registerCallback("registerMemberCallback", [parentWidget](String const& widgetName, String const& name, LuaFunction callback) { if (auto list = parentWidget->fetchChild(widgetName)){ list->registerMemberCallback(name, [callback](Widget* widget) { callback.invoke(widget->name(), widget->data()); }); } }); callbacks.registerCallback("itemGridItems", [parentWidget](String const& widgetName) { if (auto itemGrid = parentWidget->fetchChild(widgetName)) return itemGrid->bag()->toJson(); return Json(); }); callbacks.registerCallback("itemSlotItem", [parentWidget](String const& widgetName) -> Maybe { if (auto itemSlot = parentWidget->fetchChild(widgetName)) { if (itemSlot->item()) return itemSlot->item()->descriptor().toJson(); } return {}; }); callbacks.registerCallback("setItemSlotItem", [parentWidget](String const& widgetName, Json const& item) { if (auto itemSlot = parentWidget->fetchChild(widgetName)) { auto itemDb = Root::singleton().itemDatabase(); itemSlot->setItem(itemDb->fromJson(item)); } }); callbacks.registerCallback("setItemSlotProgress", [parentWidget](String const& widgetName, float progress) { if (auto itemSlot = parentWidget->fetchChild(widgetName)) { itemSlot->setProgress(progress); } }); callbacks.registerCallback("addFlowImage", [parentWidget](String const& widgetName, String const& childName, String const& image) { if (auto flow = parentWidget->fetchChild(widgetName)) { WidgetPtr newChild = make_shared(image); flow->addChild(childName, newChild); } }); return callbacks; } }