Skip to content

Commit

Permalink
feat: double-click handlers for items (rather than a global handler) (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
v-ein authored Jan 12, 2023
1 parent 334a216 commit ea2c43b
Show file tree
Hide file tree
Showing 11 changed files with 160 additions and 0 deletions.
23 changes: 23 additions & 0 deletions dearpygui/dearpygui.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions src/mvAppItem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1038,6 +1038,7 @@ DearPyGui::GetEntityDesciptionFlags(mvAppItemType type)
case mvAppItemType::mvActivatedHandler:
case mvAppItemType::mvActiveHandler:
case mvAppItemType::mvClickedHandler:
case mvAppItemType::mvDoubleClickedHandler:
case mvAppItemType::mvDeactivatedAfterEditHandler:
case mvAppItemType::mvDeactivatedHandler:
case mvAppItemType::mvEditedHandler:
Expand Down Expand Up @@ -1248,6 +1249,7 @@ DearPyGui::GetAllowableParents(mvAppItemType type)
case mvAppItemType::mvActivatedHandler:
case mvAppItemType::mvActiveHandler:
case mvAppItemType::mvClickedHandler:
case mvAppItemType::mvDoubleClickedHandler:
case mvAppItemType::mvDeactivatedAfterEditHandler:
case mvAppItemType::mvDeactivatedHandler:
case mvAppItemType::mvEditedHandler:
Expand Down Expand Up @@ -1562,6 +1564,7 @@ DearPyGui::GetAllowableChildren(mvAppItemType type)
MV_ADD_CHILD(mvAppItemType::mvActivatedHandler),
MV_ADD_CHILD(mvAppItemType::mvActiveHandler),
MV_ADD_CHILD(mvAppItemType::mvClickedHandler),
MV_ADD_CHILD(mvAppItemType::mvDoubleClickedHandler),
MV_ADD_CHILD(mvAppItemType::mvDeactivatedAfterEditHandler),
MV_ADD_CHILD(mvAppItemType::mvDeactivatedHandler),
MV_ADD_CHILD(mvAppItemType::mvEditedHandler),
Expand Down Expand Up @@ -1642,6 +1645,7 @@ DearPyGui::GetAllowableChildren(mvAppItemType type)
MV_ADD_CHILD(mvAppItemType::mvActivatedHandler),
MV_ADD_CHILD(mvAppItemType::mvActiveHandler),
MV_ADD_CHILD(mvAppItemType::mvClickedHandler),
MV_ADD_CHILD(mvAppItemType::mvDoubleClickedHandler),
MV_ADD_CHILD(mvAppItemType::mvDeactivatedAfterEditHandler),
MV_ADD_CHILD(mvAppItemType::mvDeactivatedHandler),
MV_ADD_CHILD(mvAppItemType::mvEditedHandler),
Expand All @@ -1662,6 +1666,7 @@ DearPyGui::GetAllowableChildren(mvAppItemType type)
MV_ADD_CHILD(mvAppItemType::mvActivatedHandler),
MV_ADD_CHILD(mvAppItemType::mvActiveHandler),
MV_ADD_CHILD(mvAppItemType::mvClickedHandler),
MV_ADD_CHILD(mvAppItemType::mvDoubleClickedHandler),
MV_ADD_CHILD(mvAppItemType::mvDeactivatedAfterEditHandler),
MV_ADD_CHILD(mvAppItemType::mvDeactivatedHandler),
MV_ADD_CHILD(mvAppItemType::mvEditedHandler),
Expand All @@ -1677,6 +1682,7 @@ DearPyGui::GetAllowableChildren(mvAppItemType type)
MV_ADD_CHILD(mvAppItemType::mvNodeAttribute),
MV_ADD_CHILD(mvAppItemType::mvActiveHandler),
MV_ADD_CHILD(mvAppItemType::mvClickedHandler),
MV_ADD_CHILD(mvAppItemType::mvDoubleClickedHandler),
MV_ADD_CHILD(mvAppItemType::mvHoverHandler),
MV_ADD_CHILD(mvAppItemType::mvVisibleHandler),
MV_ADD_CHILD(mvAppItemType::mvDragPayload),
Expand Down Expand Up @@ -1758,6 +1764,7 @@ DearPyGui::GetAllowableChildren(mvAppItemType type)
MV_ADD_CHILD(mvAppItemType::mvActivatedHandler),
MV_ADD_CHILD(mvAppItemType::mvActiveHandler),
MV_ADD_CHILD(mvAppItemType::mvClickedHandler),
MV_ADD_CHILD(mvAppItemType::mvDoubleClickedHandler),
MV_ADD_CHILD(mvAppItemType::mvDeactivatedAfterEditHandler),
MV_ADD_CHILD(mvAppItemType::mvDeactivatedHandler),
MV_ADD_CHILD(mvAppItemType::mvEditedHandler),
Expand Down Expand Up @@ -4838,6 +4845,21 @@ DearPyGui::GetEntityParser(mvAppItemType type)
setup.category = { "Widgets", "Events" };
break;
}
case mvAppItemType::mvDoubleClickedHandler:
{
AddCommonArgs(args, (CommonParserArgs)(
MV_PARSER_ARG_ID |
MV_PARSER_ARG_SHOW |
MV_PARSER_ARG_PARENT |
MV_PARSER_ARG_CALLBACK)
);

args.push_back({ mvPyDataType::Integer, "button", mvArgType::POSITIONAL_ARG, "-1", "Submits callback for all mouse buttons" });

setup.about = "Adds a double click handler.";
setup.category = { "Widgets", "Events" };
break;
}
case mvAppItemType::mvDragPayload:
{
AddCommonArgs(args, (CommonParserArgs)(
Expand Down
1 change: 1 addition & 0 deletions src/mvAppItem.h
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@ GetEntityCommand(mvAppItemType type)
case mvAppItemType::mvDeactivatedAfterEditHandler: return "add_item_deactivated_after_edit_handler";
case mvAppItemType::mvToggledOpenHandler: return "add_item_toggled_open_handler";
case mvAppItemType::mvClickedHandler: return "add_item_clicked_handler";
case mvAppItemType::mvDoubleClickedHandler: return "add_item_double_clicked_handler";
case mvAppItemType::mvDragPayload: return "add_drag_payload";
case mvAppItemType::mvResizeHandler: return "add_item_resize_handler";
case mvAppItemType::mvFont: return "add_font";
Expand Down
5 changes: 5 additions & 0 deletions src/mvAppItemState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ ResetAppItemState(mvAppItemState& state)
state.leftclicked = false;
state.rightclicked = false;
state.middleclicked = false;
state.doubleclicked.fill(false);
state.visible = false;
state.edited = false;
state.activated = false;
Expand All @@ -32,6 +33,10 @@ UpdateAppItemState(mvAppItemState& state)
state.leftclicked = ImGui::IsItemClicked();
state.rightclicked = ImGui::IsItemClicked(1);
state.middleclicked = ImGui::IsItemClicked(2);
for (int i = 0; i < state.doubleclicked.size(); i++)
{
state.doubleclicked[i] = IsItemDoubleClicked(i);
}
state.visible = ImGui::IsItemVisible();
state.edited = ImGui::IsItemEdited();
state.activated = ImGui::IsItemActivated();
Expand Down
7 changes: 7 additions & 0 deletions src/mvAppItemState.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "mvCore.h"
#include <array>

#ifndef PyObject_HEAD
struct _object;
Expand Down Expand Up @@ -57,6 +58,11 @@ b8 IsItemDeactivatedAfterEdit(mvAppItemState& state, i32 frameDelay = 0);
b8 IsItemToogledOpen (mvAppItemState& state, i32 frameDelay = 0);
b8 IsItemRectSizeResized (mvAppItemState& state, i32 frameDelay = 0);

inline b8 IsItemDoubleClicked(ImGuiMouseButton mouse_button)
{
return ImGui::IsMouseDoubleClicked(mouse_button) && ImGui::IsItemHovered(ImGuiHoveredFlags_None);
}

struct mvAppItemState
{
b8 hovered = false;
Expand All @@ -65,6 +71,7 @@ struct mvAppItemState
b8 leftclicked = false;
b8 rightclicked = false;
b8 middleclicked = false;
std::array<b8, 5> doubleclicked = {};
b8 visible = false;
b8 edited = false;
b8 activated = false;
Expand Down
1 change: 1 addition & 0 deletions src/mvAppItemTypes.inc
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@
X( mvDeactivatedAfterEditHandler ) \
X( mvToggledOpenHandler ) \
X( mvClickedHandler ) \
X( mvDoubleClickedHandler ) \
X( mvDragPayload ) \
X( mvResizeHandler ) \
X( mvFont ) \
Expand Down
12 changes: 12 additions & 0 deletions src/mvBasicWidgets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3034,6 +3034,10 @@ DearPyGui::draw_simple_plot(ImDrawList* drawlist, mvAppItem& item, const mvSimpl
item.state.leftclicked = ImGui::IsItemClicked();
item.state.rightclicked = ImGui::IsItemClicked(1);
item.state.middleclicked = ImGui::IsItemClicked(2);
for (int i = 0; i < item.state.doubleclicked.size(); i++)
{
item.state.doubleclicked[i] = IsItemDoubleClicked(i);
}
item.state.visible = ImGui::IsItemVisible();
item.state.rectMin = { ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y };
item.state.rectMax = { ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y };
Expand Down Expand Up @@ -4885,6 +4889,10 @@ DearPyGui::draw_radio_button(ImDrawList* drawlist, mvAppItem& item, mvRadioButto
item.state.leftclicked = ImGui::IsItemClicked();
item.state.rightclicked = ImGui::IsItemClicked(1);
item.state.middleclicked = ImGui::IsItemClicked(2);
for (int i = 0; i < item.state.doubleclicked.size(); i++)
{
item.state.doubleclicked[i] = IsItemDoubleClicked(i);
}
item.state.visible = ImGui::IsItemVisible();
item.state.activated = ImGui::IsItemActivated();
item.state.deactivated = ImGui::IsItemDeactivated();
Expand Down Expand Up @@ -6020,6 +6028,10 @@ DearPyGui::draw_text(ImDrawList* drawlist, mvAppItem& item, mvTextConfig& config
item.state.leftclicked |= ImGui::IsItemClicked();
item.state.rightclicked |= ImGui::IsItemClicked(1);
item.state.middleclicked |= ImGui::IsItemClicked(2);
for (int i = 0; i < item.state.doubleclicked.size(); i++)
{
item.state.doubleclicked[i] = IsItemDoubleClicked(i);
}
item.state.visible |= ImGui::IsItemVisible();
item.state.edited |= ImGui::IsItemEdited();
item.state.activated |= ImGui::IsItemActivated();
Expand Down
8 changes: 8 additions & 0 deletions src/mvContainers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -856,6 +856,10 @@ DearPyGui::draw_tab(ImDrawList* drawlist, mvAppItem& item, mvTabConfig& config)
item.state.leftclicked = ImGui::IsItemClicked();
item.state.rightclicked = ImGui::IsItemClicked(1);
item.state.middleclicked = ImGui::IsItemClicked(2);
for (int i = 0; i < item.state.doubleclicked.size(); i++)
{
item.state.doubleclicked[i] = IsItemDoubleClicked(i);
}
item.state.visible = ImGui::IsItemVisible();
item.state.activated = ImGui::IsItemActivated();
item.state.deactivated = ImGui::IsItemDeactivated();
Expand Down Expand Up @@ -900,6 +904,10 @@ DearPyGui::draw_tab(ImDrawList* drawlist, mvAppItem& item, mvTabConfig& config)
item.state.leftclicked = ImGui::IsItemClicked();
item.state.rightclicked = ImGui::IsItemClicked(1);
item.state.middleclicked = ImGui::IsItemClicked(2);
for (int i = 0; i < item.state.doubleclicked.size(); i++)
{
item.state.doubleclicked[i] = IsItemDoubleClicked(i);
}
item.state.visible = ImGui::IsItemVisible();
item.state.activated = ImGui::IsItemActivated();
item.state.deactivated = ImGui::IsItemDeactivated();
Expand Down
64 changes: 64 additions & 0 deletions src/mvItemHandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ void mvItemHandlerRegistry::onBind(mvAppItem* item)
break;
}

case mvAppItemType::mvDoubleClickedHandler:
{
// if an item can be clicked, it can be double clicked as well
if (!(applicableState & MV_STATE_CLICKED))
mvThrowPythonError(mvErrorCode::mvNone, "bind_item_handler_registry",
"Item Handler Registry includes inapplicable handler: mvDoubleClickedHandler", item);
break;
}

case mvAppItemType::mvDeactivatedAfterEditHandler:
{
if (!(applicableState & MV_STATE_DEACTIVATEDAE))
Expand Down Expand Up @@ -228,6 +237,61 @@ void mvClickedHandler::applySpecificTemplate(mvAppItem* item)
_button = titem->_button;
}

void mvDoubleClickedHandler::customAction(void* data)
{
mvAppItemState* state = static_cast<mvAppItemState*>(data);

int i = (_button < 0)? 0 : _button ;
int end = (_button < 0)? state->doubleclicked.size() : (i + 1);

for (; i < end; i++)
{
if (state->doubleclicked[i])
{
mvSubmitCallback([=]()
{
mvPyObject pArgs(PyTuple_New(2));
PyTuple_SetItem(pArgs, 0, ToPyInt(i));
PyTuple_SetItem(pArgs, 1, ToPyUUID(state->parent)); // steals data, so don't deref
if (config.alias.empty())
mvRunCallback(getCallback(false), uuid, pArgs, config.user_data);
else
mvRunCallback(getCallback(false), config.alias, pArgs, config.user_data);
});
}
}
}

void mvDoubleClickedHandler::handleSpecificRequiredArgs(PyObject* dict)
{
if (!VerifyRequiredArguments(GetParsers()[GetEntityCommand(type)], dict))
return;

_button = ToInt(PyTuple_GetItem(dict, 0));
}

void mvDoubleClickedHandler::handleSpecificKeywordArgs(PyObject* dict)
{
if (dict == nullptr)
return;

if (PyObject* item = PyDict_GetItemString(dict, "button")) _button = ToInt(item);
}

void mvDoubleClickedHandler::getSpecificConfiguration(PyObject* dict)
{
if (dict == nullptr)
return;

PyDict_SetItemString(dict, "button", ToPyInt(_button));
}

void mvDoubleClickedHandler::applySpecificTemplate(mvAppItem* item)
{
auto titem = static_cast<mvDoubleClickedHandler*>(item);
_button = titem->_button;
}

void mvDeactivatedAfterEditHandler::customAction(void* data)
{

Expand Down
13 changes: 13 additions & 0 deletions src/mvItemHandlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,19 @@ class mvClickedHandler : public mvAppItem
void applySpecificTemplate(mvAppItem* item) override;
};

class mvDoubleClickedHandler : public mvAppItem
{
public:
int _button = -1;
explicit mvDoubleClickedHandler(mvUUID uuid) : mvAppItem(uuid) {}
void draw(ImDrawList* drawlist, float x, float y) override {}
void customAction(void* data = nullptr) override;
void handleSpecificRequiredArgs(PyObject* dict) override;
void handleSpecificKeywordArgs(PyObject* dict) override;
void getSpecificConfiguration(PyObject* dict) override;
void applySpecificTemplate(mvAppItem* item) override;
};

class mvDeactivatedAfterEditHandler : public mvAppItem
{
public:
Expand Down
4 changes: 4 additions & 0 deletions src/mvNodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,10 @@ void mvNode::draw(ImDrawList* drawlist, float x, float y)
state.leftclicked = ImGui::IsItemClicked();
state.rightclicked = ImGui::IsItemClicked(1);
state.middleclicked = ImGui::IsItemClicked(2);
for (int i = 0; i < state.doubleclicked.size(); i++)
{
state.doubleclicked[i] = IsItemDoubleClicked(i);
}
state.visible = ImGui::IsItemVisible();

for (auto& item : childslots[1])
Expand Down

0 comments on commit ea2c43b

Please sign in to comment.