[lua] Add possibility to display a Dialog as a popup menu

* Added new Dialog:menuItem{} widget
* Added Dialog:showMenu{} function
This commit is contained in:
David Capello 2023-01-12 11:02:40 -03:00
parent 39d1fb56d4
commit 5953e93402

View File

@ -33,6 +33,7 @@
#include "ui/grid.h"
#include "ui/label.h"
#include "ui/manager.h"
#include "ui/menu.h"
#include "ui/message.h"
#include "ui/separator.h"
#include "ui/slider.h"
@ -60,10 +61,10 @@ std::vector<Dialog*> all_dialogs;
struct Dialog {
ui::Window window;
ui::VBox vbox;
ui::Grid grid;
ui::HBox* hbox = nullptr;
bool autoNewRow = false;
WidgetsList mainWidgets;
std::map<std::string, ui::Widget*> dataWidgets;
std::map<std::string, ui::Widget*> labelWidgets;
int currentRadioGroup = 0;
@ -142,16 +143,21 @@ struct Dialog {
it->second->setText(text);
}
Display* parentDisplay() const {
Display* parentDisplay = window.parentDisplay();
if (!parentDisplay) {
const auto mainWindow = App::instance()->mainWindow();
parentDisplay = mainWindow->display();
}
return parentDisplay;
}
gfx::Rect getWindowBounds() const {
gfx::Rect bounds = window.bounds();
// Bounds in scripts will be relative to the parent window
// origin/scale (or main window if a parent window wasn't specified).
if (window.ownDisplay()) {
const Display* parentDisplay = window.parentDisplay();
if (!parentDisplay) {
const auto mainWindow = App::instance()->mainWindow();
parentDisplay = mainWindow->display();
}
const Display* parentDisplay = this->parentDisplay();
const int scale = parentDisplay->scale();
const gfx::Point dialogOrigin = window.display()->nativeWindow()->contentRect().origin();
const gfx::Point mainOrigin = parentDisplay->nativeWindow()->contentRect().origin();
@ -164,12 +170,7 @@ struct Dialog {
if (window.ownDisplay()) {
window.expandWindow(rc.size());
const Display* parentDisplay = window.parentDisplay();
if (!parentDisplay) {
const auto mainWindow = App::instance()->mainWindow();
parentDisplay = mainWindow->display();
}
Display* parentDisplay = this->parentDisplay();
const int scale = parentDisplay->scale();
const gfx::Point mainOrigin = parentDisplay->nativeWindow()->contentRect().origin();
gfx::Rect frame = window.display()->nativeWindow()->contentRect();
@ -349,6 +350,54 @@ int Dialog_show(lua_State* L)
return 1;
}
namespace {
class MoveChildren {
public:
MoveChildren(Dialog* dlg, Widget* to)
: m_dlg(dlg)
, m_to(to) {
for (auto child : m_dlg->mainWidgets) {
m_oldParents[child] = child->parent();
m_to->addChild(child);
}
}
~MoveChildren() {
for (auto child : m_dlg->mainWidgets)
m_oldParents[child]->addChild(child);
}
private:
Dialog* m_dlg;
Widget* m_to;
std::map<Widget*, Widget*> m_oldParents;
};
}
int Dialog_showMenu(lua_State* L)
{
auto dlg = get_obj<Dialog>(L, 1);
Menu popup;
MoveChildren moveChildren(dlg, &popup);
// By default show the menu in the mouse position
gfx::Point pt =
dlg->parentDisplay()->nativeWindow()
->pointFromScreen(ui::get_mouse_position());
if (lua_istable(L, 2)) {
if (lua_getfield(L, 2, "position") != LUA_TNIL) {
pt = convert_args_into_point(L, -1);
}
lua_pop(L, 1);
}
dlg->refShow(L);
popup.showPopup(pt, dlg->parentDisplay());
dlg->unrefShow();
lua_pushvalue(L, 1);
return 1;
}
int Dialog_close(lua_State* L)
{
auto dlg = get_obj<Dialog>(L, 1);
@ -447,6 +496,7 @@ int Dialog_add_widget(lua_State* L, Widget* widget)
dlg->hbox = hbox;
}
dlg->mainWidgets.push_back(widget);
widget->setExpansive(hexpand);
dlg->hbox->addChild(widget);
@ -503,6 +553,7 @@ int Dialog_separator(lua_State* L)
dlg->dataWidgets[id] = widget;
}
dlg->mainWidgets.push_back(widget);
dlg->grid.addChildInCell(widget, 2, 1, ui::HORIZONTAL | ui::TOP);
dlg->hbox = nullptr;
@ -529,6 +580,8 @@ int Dialog_label(lua_State* L)
template<typename T>
int Dialog_button_base(lua_State* L, T** outputWidget = nullptr)
{
auto dlg = get_obj<Dialog>(L, 1);
std::string text;
if (lua_istable(L, 2)) {
int type = lua_getfield(L, 2, "text");
@ -555,20 +608,27 @@ int Dialog_button_base(lua_State* L, T** outputWidget = nullptr)
type = lua_getfield(L, 2, "onclick");
if (type == LUA_TFUNCTION) {
auto dlg = get_obj<Dialog>(L, 1);
Dialog_connect_signal(
L, 1, widget->Click,
[dlg, widget](lua_State* L){
if (widget->type() == ui::kButtonWidget)
dlg->lastButton = widget;
// Do nothing
});
closeWindowByDefault = false;
}
lua_pop(L, 1);
}
if (closeWindowByDefault)
widget->Click.connect([widget](ui::Event&){ widget->closeWindow(); });
if (closeWindowByDefault) {
widget->Click.connect([dlg, widget](){
widget->closeWindow();
});
}
if (widget->type() == ui::kButtonWidget ||
widget->type() == ui::kMenuItemWidget) {
widget->Click.connect([dlg, widget](){
dlg->lastButton = widget;
});
}
return Dialog_add_widget(L, widget);
}
@ -608,6 +668,11 @@ int Dialog_radio(lua_State* L)
return res;
}
int Dialog_menuItem(lua_State* L)
{
return Dialog_button_base<ui::MenuItem>(L);
}
int Dialog_entry(lua_State* L)
{
std::string text;
@ -1329,6 +1394,7 @@ int Dialog_get_data(lua_State* L)
case ui::kButtonWidget:
case ui::kCheckWidget:
case ui::kRadioWidget:
case ui::kMenuItemWidget:
lua_pushboolean(L, widget->isSelected() ||
dlg->window.closer() == widget ||
dlg->lastButton == widget);
@ -1518,6 +1584,7 @@ int Dialog_set_bounds(lua_State* L)
const luaL_Reg Dialog_methods[] = {
{ "__gc", Dialog_gc },
{ "show", Dialog_show },
{ "showMenu", Dialog_showMenu },
{ "close", Dialog_close },
{ "newrow", Dialog_newrow },
{ "separator", Dialog_separator },
@ -1525,6 +1592,7 @@ const luaL_Reg Dialog_methods[] = {
{ "button", Dialog_button },
{ "check", Dialog_check },
{ "radio", Dialog_radio },
{ "menuItem", Dialog_menuItem },
{ "entry", Dialog_entry },
{ "number", Dialog_number },
{ "slider", Dialog_slider },