Add support for exiting formspecs by doubleclicking outside
parent
763a511ca5
commit
003634e049
|
@ -134,7 +134,6 @@ function ui.handle_events(event)
|
||||||
local retval = value:handle_events(event)
|
local retval = value:handle_events(event)
|
||||||
|
|
||||||
if retval then
|
if retval then
|
||||||
print("event handled by: " .. key)
|
|
||||||
return retval
|
return retval
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -46,6 +46,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#include "gettime.h"
|
#include "gettime.h"
|
||||||
#include "gettext.h"
|
#include "gettext.h"
|
||||||
#include "scripting_game.h"
|
#include "scripting_game.h"
|
||||||
|
#include "porting.h"
|
||||||
|
|
||||||
#define MY_CHECKPOS(a,b) \
|
#define MY_CHECKPOS(a,b) \
|
||||||
if (v_pos.size() != 2) { \
|
if (v_pos.size() != 2) { \
|
||||||
|
@ -91,6 +92,12 @@ GUIFormSpecMenu::GUIFormSpecMenu(irr::IrrlichtDevice* dev,
|
||||||
current_keys_pending.key_enter = false;
|
current_keys_pending.key_enter = false;
|
||||||
current_keys_pending.key_escape = false;
|
current_keys_pending.key_escape = false;
|
||||||
|
|
||||||
|
m_doubleclickdetect[0].time = 0;
|
||||||
|
m_doubleclickdetect[1].time = 0;
|
||||||
|
|
||||||
|
m_doubleclickdetect[0].pos = v2s32(0, 0);
|
||||||
|
m_doubleclickdetect[1].pos = v2s32(0, 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GUIFormSpecMenu::~GUIFormSpecMenu()
|
GUIFormSpecMenu::~GUIFormSpecMenu()
|
||||||
|
@ -1171,9 +1178,9 @@ void GUIFormSpecMenu::parseImageButton(parserData* data,std::string element,
|
||||||
if (parts[6] == "false")
|
if (parts[6] == "false")
|
||||||
drawborder = false;
|
drawborder = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string pressed_image_name = "";
|
std::string pressed_image_name = "";
|
||||||
|
|
||||||
if ((parts.size() == 8)) {
|
if ((parts.size() == 8)) {
|
||||||
pressed_image_name = parts[7];
|
pressed_image_name = parts[7];
|
||||||
}
|
}
|
||||||
|
@ -1265,9 +1272,11 @@ void GUIFormSpecMenu::parseTabHeader(parserData* data,std::string element)
|
||||||
geom.X = data->screensize.Y;
|
geom.X = data->screensize.Y;
|
||||||
geom.Y = 30;
|
geom.Y = 30;
|
||||||
|
|
||||||
core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y, pos.X+geom.X, pos.Y+geom.Y);
|
core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y, pos.X+geom.X,
|
||||||
|
pos.Y+geom.Y);
|
||||||
|
|
||||||
gui::IGUITabControl *e = Environment->addTabControl(rect,this,show_background,show_border,spec.fid);
|
gui::IGUITabControl *e = Environment->addTabControl(rect, this,
|
||||||
|
show_background, show_border, spec.fid);
|
||||||
|
|
||||||
if (spec.fname == data->focused_fieldname) {
|
if (spec.fname == data->focused_fieldname) {
|
||||||
Environment->setFocus(e);
|
Environment->setFocus(e);
|
||||||
|
@ -1276,7 +1285,7 @@ void GUIFormSpecMenu::parseTabHeader(parserData* data,std::string element)
|
||||||
e->setNotClipped(true);
|
e->setNotClipped(true);
|
||||||
|
|
||||||
for (unsigned int i=0; i< buttons.size(); i++) {
|
for (unsigned int i=0; i< buttons.size(); i++) {
|
||||||
e->addTab(narrow_to_wide(buttons[i]).c_str(),-1);
|
e->addTab(narrow_to_wide(buttons[i]).c_str(), -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((tab_index >= 0) &&
|
if ((tab_index >= 0) &&
|
||||||
|
@ -1287,14 +1296,17 @@ void GUIFormSpecMenu::parseTabHeader(parserData* data,std::string element)
|
||||||
m_fields.push_back(spec);
|
m_fields.push_back(spec);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
errorstream<< "Invalid TabHeader element(" << parts.size() << "): '" << element << "'" << std::endl;
|
errorstream << "Invalid TabHeader element(" << parts.size() << "): '"
|
||||||
|
<< element << "'" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIFormSpecMenu::parseItemImageButton(parserData* data,std::string element)
|
void GUIFormSpecMenu::parseItemImageButton(parserData* data,std::string element)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (m_gamedef == 0) {
|
if (m_gamedef == 0) {
|
||||||
errorstream<<"WARNING: invalid use of item_image_button with m_gamedef==0"<<std::endl;
|
errorstream <<
|
||||||
|
"WARNING: invalid use of item_image_button with m_gamedef==0"
|
||||||
|
<< std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1414,7 +1426,7 @@ void GUIFormSpecMenu::parseListColors(parserData* data,std::string element)
|
||||||
if ((parts.size() == 2) || (parts.size() == 3) || (parts.size() == 5)) {
|
if ((parts.size() == 2) || (parts.size() == 3) || (parts.size() == 5)) {
|
||||||
parseColor(parts[0], m_slotbg_n, false);
|
parseColor(parts[0], m_slotbg_n, false);
|
||||||
parseColor(parts[1], m_slotbg_h, false);
|
parseColor(parts[1], m_slotbg_h, false);
|
||||||
|
|
||||||
if (parts.size() >= 3) {
|
if (parts.size() >= 3) {
|
||||||
if (parseColor(parts[2], m_slotbordercolor, false)) {
|
if (parseColor(parts[2], m_slotbordercolor, false)) {
|
||||||
m_slotborder = true;
|
m_slotborder = true;
|
||||||
|
@ -1628,9 +1640,9 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
||||||
// A proceed button is added if there is no size[] element
|
// A proceed button is added if there is no size[] element
|
||||||
mydata.bp_set = 0;
|
mydata.bp_set = 0;
|
||||||
|
|
||||||
|
|
||||||
/* Convert m_init_draw_spec to m_inventorylists */
|
/* Convert m_init_draw_spec to m_inventorylists */
|
||||||
|
|
||||||
m_inventorylists.clear();
|
m_inventorylists.clear();
|
||||||
m_images.clear();
|
m_images.clear();
|
||||||
m_backgrounds.clear();
|
m_backgrounds.clear();
|
||||||
|
@ -1710,7 +1722,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
||||||
GUIFormSpecMenu::ItemSpec GUIFormSpecMenu::getItemAtPos(v2s32 p) const
|
GUIFormSpecMenu::ItemSpec GUIFormSpecMenu::getItemAtPos(v2s32 p) const
|
||||||
{
|
{
|
||||||
core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y);
|
core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y);
|
||||||
|
|
||||||
for(u32 i=0; i<m_inventorylists.size(); i++)
|
for(u32 i=0; i<m_inventorylists.size(); i++)
|
||||||
{
|
{
|
||||||
const ListDrawSpec &s = m_inventorylists[i];
|
const ListDrawSpec &s = m_inventorylists[i];
|
||||||
|
@ -1741,7 +1753,7 @@ void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase)
|
||||||
gui::IGUISkin* skin = Environment->getSkin();
|
gui::IGUISkin* skin = Environment->getSkin();
|
||||||
if (skin)
|
if (skin)
|
||||||
font = skin->getFont();
|
font = skin->getFont();
|
||||||
|
|
||||||
Inventory *inv = m_invmgr->getInventory(s.inventoryloc);
|
Inventory *inv = m_invmgr->getInventory(s.inventoryloc);
|
||||||
if(!inv){
|
if(!inv){
|
||||||
infostream<<"GUIFormSpecMenu::drawList(): WARNING: "
|
infostream<<"GUIFormSpecMenu::drawList(): WARNING: "
|
||||||
|
@ -1758,9 +1770,9 @@ void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase)
|
||||||
<<std::endl;
|
<<std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y);
|
core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y);
|
||||||
|
|
||||||
for(s32 i=0; i<s.geom.X*s.geom.Y; i++)
|
for(s32 i=0; i<s.geom.X*s.geom.Y; i++)
|
||||||
{
|
{
|
||||||
s32 item_i = i + s.start_item_i;
|
s32 item_i = i + s.start_item_i;
|
||||||
|
@ -1855,7 +1867,7 @@ void GUIFormSpecMenu::drawSelectedItem()
|
||||||
gui::IGUISkin* skin = Environment->getSkin();
|
gui::IGUISkin* skin = Environment->getSkin();
|
||||||
if (skin)
|
if (skin)
|
||||||
font = skin->getFont();
|
font = skin->getFont();
|
||||||
|
|
||||||
Inventory *inv = m_invmgr->getInventory(m_selected_item->inventoryloc);
|
Inventory *inv = m_invmgr->getInventory(m_selected_item->inventoryloc);
|
||||||
assert(inv);
|
assert(inv);
|
||||||
InventoryList *list = inv->getList(m_selected_item->listname);
|
InventoryList *list = inv->getList(m_selected_item->listname);
|
||||||
|
@ -1886,7 +1898,7 @@ void GUIFormSpecMenu::drawMenu()
|
||||||
if (!skin)
|
if (!skin)
|
||||||
return;
|
return;
|
||||||
video::IVideoDriver* driver = Environment->getVideoDriver();
|
video::IVideoDriver* driver = Environment->getVideoDriver();
|
||||||
|
|
||||||
v2u32 screenSize = driver->getScreenSize();
|
v2u32 screenSize = driver->getScreenSize();
|
||||||
core::rect<s32> allbg(0, 0, screenSize.X , screenSize.Y);
|
core::rect<s32> allbg(0, 0, screenSize.X , screenSize.Y);
|
||||||
if (m_bgfullscreen)
|
if (m_bgfullscreen)
|
||||||
|
@ -1930,7 +1942,7 @@ void GUIFormSpecMenu::drawMenu()
|
||||||
errorstream << "\t" << spec.name << std::endl;
|
errorstream << "\t" << spec.name << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Draw Boxes
|
Draw Boxes
|
||||||
*/
|
*/
|
||||||
|
@ -1979,7 +1991,7 @@ void GUIFormSpecMenu::drawMenu()
|
||||||
errorstream << "\t" << spec.name << std::endl;
|
errorstream << "\t" << spec.name << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Draw item images
|
Draw item images
|
||||||
*/
|
*/
|
||||||
|
@ -2004,7 +2016,7 @@ void GUIFormSpecMenu::drawMenu()
|
||||||
core::dimension2di(texture->getOriginalSize())),
|
core::dimension2di(texture->getOriginalSize())),
|
||||||
NULL/*&AbsoluteClippingRect*/, colors, true);
|
NULL/*&AbsoluteClippingRect*/, colors, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Draw items
|
Draw items
|
||||||
Phase 0: Item slot rectangles
|
Phase 0: Item slot rectangles
|
||||||
|
@ -2021,7 +2033,7 @@ void GUIFormSpecMenu::drawMenu()
|
||||||
Call base class
|
Call base class
|
||||||
*/
|
*/
|
||||||
gui::IGUIElement::draw();
|
gui::IGUIElement::draw();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Draw fields/buttons tooltips
|
Draw fields/buttons tooltips
|
||||||
*/
|
*/
|
||||||
|
@ -2046,7 +2058,7 @@ void GUIFormSpecMenu::drawMenu()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Draw dragged item stack
|
Draw dragged item stack
|
||||||
*/
|
*/
|
||||||
|
@ -2276,6 +2288,17 @@ void GUIFormSpecMenu::acceptInput(FormspecQuitMode quitmode=quit_mode_no)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isChild(gui::IGUIElement * tocheck, gui::IGUIElement * parent)
|
||||||
|
{
|
||||||
|
while(tocheck != NULL) {
|
||||||
|
if (tocheck == parent) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
tocheck = tocheck->getParent();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool GUIFormSpecMenu::preprocessEvent(const SEvent& event)
|
bool GUIFormSpecMenu::preprocessEvent(const SEvent& event)
|
||||||
{
|
{
|
||||||
// Fix Esc/Return key being eaten by checkboxen and tables
|
// Fix Esc/Return key being eaten by checkboxen and tables
|
||||||
|
@ -2306,6 +2329,64 @@ bool GUIFormSpecMenu::preprocessEvent(const SEvent& event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.EventType == EET_MOUSE_INPUT_EVENT) {
|
||||||
|
s32 x = event.MouseInput.X;
|
||||||
|
s32 y = event.MouseInput.Y;
|
||||||
|
gui::IGUIElement *hovered =
|
||||||
|
Environment->getRootGUIElement()->getElementFromPoint(
|
||||||
|
core::position2d<s32>(x, y));
|
||||||
|
|
||||||
|
if (!isChild(hovered,this)) {
|
||||||
|
if (DoubleClickDetection(event)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
bool GUIFormSpecMenu::DoubleClickDetection(const SEvent event)
|
||||||
|
{
|
||||||
|
if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) {
|
||||||
|
m_doubleclickdetect[0].pos = m_doubleclickdetect[1].pos;
|
||||||
|
m_doubleclickdetect[0].time = m_doubleclickdetect[1].time;
|
||||||
|
|
||||||
|
m_doubleclickdetect[1].pos = m_pointer;
|
||||||
|
m_doubleclickdetect[1].time = getTimeMs();
|
||||||
|
}
|
||||||
|
else if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP) {
|
||||||
|
u32 delta = porting::getDeltaMs(m_doubleclickdetect[0].time, getTimeMs());
|
||||||
|
if (delta > 400) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
double squaredistance =
|
||||||
|
m_doubleclickdetect[0].pos
|
||||||
|
.getDistanceFromSQ(m_doubleclickdetect[1].pos);
|
||||||
|
|
||||||
|
if (squaredistance > (30*30)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SEvent* translated = new SEvent();
|
||||||
|
assert(translated != 0);
|
||||||
|
//translate doubleclick to escape
|
||||||
|
memset(translated, 0, sizeof(SEvent));
|
||||||
|
translated->EventType = irr::EET_KEY_INPUT_EVENT;
|
||||||
|
translated->KeyInput.Key = KEY_ESCAPE;
|
||||||
|
translated->KeyInput.Control = false;
|
||||||
|
translated->KeyInput.Shift = false;
|
||||||
|
translated->KeyInput.PressedDown = true;
|
||||||
|
translated->KeyInput.Char = 0;
|
||||||
|
OnEvent(*translated);
|
||||||
|
|
||||||
|
// no need to send the key up event as we're already deleted
|
||||||
|
// and no one else did notice this event
|
||||||
|
delete translated;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -143,7 +143,7 @@ class GUIFormSpecMenu : public GUIModalMenu
|
||||||
v2s32 geom;
|
v2s32 geom;
|
||||||
bool scale;
|
bool scale;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FieldSpec
|
struct FieldSpec
|
||||||
{
|
{
|
||||||
FieldSpec()
|
FieldSpec()
|
||||||
|
@ -205,7 +205,7 @@ public:
|
||||||
m_current_inventory_location = current_inventory_location;
|
m_current_inventory_location = current_inventory_location;
|
||||||
regenerateGui(m_screensize_old);
|
regenerateGui(m_screensize_old);
|
||||||
}
|
}
|
||||||
|
|
||||||
// form_src is deleted by this GUIFormSpecMenu
|
// form_src is deleted by this GUIFormSpecMenu
|
||||||
void setFormSource(IFormSource *form_src)
|
void setFormSource(IFormSource *form_src)
|
||||||
{
|
{
|
||||||
|
@ -240,7 +240,7 @@ public:
|
||||||
Remove and re-add (or reposition) stuff
|
Remove and re-add (or reposition) stuff
|
||||||
*/
|
*/
|
||||||
void regenerateGui(v2u32 screensize);
|
void regenerateGui(v2u32 screensize);
|
||||||
|
|
||||||
ItemSpec getItemAtPos(v2s32 p) const;
|
ItemSpec getItemAtPos(v2s32 p) const;
|
||||||
void drawList(const ListDrawSpec &s, int phase);
|
void drawList(const ListDrawSpec &s, int phase);
|
||||||
void drawSelectedItem();
|
void drawSelectedItem();
|
||||||
|
@ -269,7 +269,7 @@ protected:
|
||||||
v2s32 spacing;
|
v2s32 spacing;
|
||||||
v2s32 imgsize;
|
v2s32 imgsize;
|
||||||
v2s32 offset;
|
v2s32 offset;
|
||||||
|
|
||||||
irr::IrrlichtDevice* m_device;
|
irr::IrrlichtDevice* m_device;
|
||||||
InventoryManager *m_invmgr;
|
InventoryManager *m_invmgr;
|
||||||
IGameDef *m_gamedef;
|
IGameDef *m_gamedef;
|
||||||
|
@ -290,7 +290,7 @@ protected:
|
||||||
ItemSpec *m_selected_item;
|
ItemSpec *m_selected_item;
|
||||||
u32 m_selected_amount;
|
u32 m_selected_amount;
|
||||||
bool m_selected_dragging;
|
bool m_selected_dragging;
|
||||||
|
|
||||||
// WARNING: BLACK MAGIC
|
// WARNING: BLACK MAGIC
|
||||||
// Used to guess and keep up with some special things the server can do.
|
// Used to guess and keep up with some special things the server can do.
|
||||||
// If name is "", no guess exists.
|
// If name is "", no guess exists.
|
||||||
|
@ -366,6 +366,20 @@ private:
|
||||||
void parseBox(parserData* data,std::string element);
|
void parseBox(parserData* data,std::string element);
|
||||||
void parseBackgroundColor(parserData* data,std::string element);
|
void parseBackgroundColor(parserData* data,std::string element);
|
||||||
void parseListColors(parserData* data,std::string element);
|
void parseListColors(parserData* data,std::string element);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check if event is part of a double click
|
||||||
|
* @param event event to evaluate
|
||||||
|
* @return true/false if a doubleclick was detected
|
||||||
|
*/
|
||||||
|
bool DoubleClickDetection(const SEvent event);
|
||||||
|
|
||||||
|
struct clickpos
|
||||||
|
{
|
||||||
|
v2s32 pos;
|
||||||
|
s32 time;
|
||||||
|
};
|
||||||
|
clickpos m_doubleclickdetect[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
class FormspecFormSource: public IFormSource
|
class FormspecFormSource: public IFormSource
|
||||||
|
|
|
@ -275,6 +275,21 @@ inline u32 getTime(TimePrecision prec)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delta calculation function taking two 32bit arguments.
|
||||||
|
* @param old_time_ms old time for delta calculation (order is relevant!)
|
||||||
|
* @param new_time_ms new time for delta calculation (order is relevant!)
|
||||||
|
* @return positive 32bit delta value
|
||||||
|
*/
|
||||||
|
inline u32 getDeltaMs(u32 old_time_ms, u32 new_time_ms)
|
||||||
|
{
|
||||||
|
if (new_time_ms >= old_time_ms) {
|
||||||
|
return (new_time_ms - old_time_ms);
|
||||||
|
} else {
|
||||||
|
return (old_time_ms - new_time_ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(linux) || defined(__linux)
|
#if defined(linux) || defined(__linux)
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue