From 0cf7ace207b803fd4e5e5829ba9617bb591f3701 Mon Sep 17 00:00:00 2001 From: Ivanzzzc <46572469+IvanNazaruk@users.noreply.github.com> Date: Sun, 1 Jan 2023 23:13:33 +0200 Subject: [PATCH] v1.0.0 --- .gitignore | 2 + DearPyGui_DragAndDrop/__init__.py | 16 ++++ DearPyGui_DragAndDrop/main.py | 145 ++++++++++++++++++++++++++++++ DearPyGui_DragAndDrop/setup.py | 64 +++++++++++++ DearPyGui_DragAndDrop/tools.py | 87 ++++++++++++++++++ Examples/EADME.md | 50 +++++++++++ Examples/example1.py | 25 ++++++ Examples/example2.py | 39 ++++++++ Examples/example3.py | 58 ++++++++++++ Examples/example4.py | 80 +++++++++++++++++ Examples/example5.py | 59 ++++++++++++ README.md | 60 +++++++++++++ pyproject.toml | 31 +++++++ 13 files changed, 716 insertions(+) create mode 100644 DearPyGui_DragAndDrop/__init__.py create mode 100644 DearPyGui_DragAndDrop/main.py create mode 100644 DearPyGui_DragAndDrop/setup.py create mode 100644 DearPyGui_DragAndDrop/tools.py create mode 100644 Examples/EADME.md create mode 100644 Examples/example1.py create mode 100644 Examples/example2.py create mode 100644 Examples/example3.py create mode 100644 Examples/example4.py create mode 100644 Examples/example5.py create mode 100644 README.md create mode 100644 pyproject.toml diff --git a/.gitignore b/.gitignore index b6e4761..6c2e3e6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +.idea/ + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/DearPyGui_DragAndDrop/__init__.py b/DearPyGui_DragAndDrop/__init__.py new file mode 100644 index 0000000..384f583 --- /dev/null +++ b/DearPyGui_DragAndDrop/__init__.py @@ -0,0 +1,16 @@ +import threading + +from . import main as __main +from . import setup as __setup +from .main import DROPEFFECT, KEYSTATE +from .main import DragAndDrop, DragAndDropDataObject +from .main import set_drag_enter, set_drag_over, set_drag_leave, set_drop +from .main import set_drop_effect, get_drop_effect + +__version__ = "1.0.0" + +def initialize(): + if isinstance(__main._DragAndDropForFunctions, type): + __main._DragAndDropForFunctions = __main._DragAndDropForFunctions() + + threading.Thread(target=__setup.setup, daemon=True).start() diff --git a/DearPyGui_DragAndDrop/main.py b/DearPyGui_DragAndDrop/main.py new file mode 100644 index 0000000..fc7463a --- /dev/null +++ b/DearPyGui_DragAndDrop/main.py @@ -0,0 +1,145 @@ +from __future__ import annotations + +import traceback +from enum import IntEnum +from pathlib import Path +from typing import Type, TypeVar, Dict, Callable, Any, Union, List + +import dearpygui.dearpygui as dpg + +DragAndDropDataObject = Union[None, str, List[Path]] +SubscriptionTag = TypeVar('SubscriptionTag', bound=int) + + +class KEYSTATE(IntEnum): + LEFT = 1 + RIGHT = 2 + SHIFT = 4 + CTRL = 8 + MIDDLE = 16 + ALT = 32 + + +class DROPEFFECT(IntEnum): + NONE = 0 + COPY = 1 + MOVE = 2 + + +_now_drop_effect: DROPEFFECT = DROPEFFECT.MOVE + + +def set_drop_effect(effect: DROPEFFECT = DROPEFFECT.NONE): + global _now_drop_effect + _now_drop_effect = effect + + +def get_drop_effect() -> DROPEFFECT: + return _now_drop_effect + + +class DragAndDrop(): + __subscribers: Dict[SubscriptionTag, Type[DragAndDrop]] = {} + __subscription_tag: SubscriptionTag = None + + def DragEnter(self, dataObject: DragAndDropDataObject, keyState: list[KEYSTATE]): + ... + + def DragOver(self, keyState: list[KEYSTATE]): + ... + + def DragLeave(self): + ... + + def Drop(self, dataObject: DragAndDropDataObject, keyState: list[KEYSTATE]): + ... + + def __init__(self): + if self.__subscription_tag: + self._unsubscribe(self.__subscription_tag) + self.__subscription_tag = self._subscribe(self) # noqa + + def __del__(self): + if self.__subscription_tag: + self._unsubscribe(self.__subscription_tag) + + @classmethod + def _subscribe(cls, self: Type[DragAndDrop]) -> SubscriptionTag: + subscription_tag = dpg.generate_uuid() + cls.__subscribers[subscription_tag] = self + return subscription_tag + + @classmethod + def _unsubscribe(self, subscription_tag: SubscriptionTag): + if subscription_tag in self.__subscribers: + del self.__subscribers[subscription_tag] + + @classmethod + def _DragEnter(cls, dataObject, keyState): + for self in cls.__subscribers.values(): + try: + self.DragEnter(dataObject, keyState) # noqa + except Exception: + traceback.print_exc() + + @classmethod + def _DragOver(cls, keyState): + for self in cls.__subscribers.values(): + try: + self.DragOver(keyState) # noqa + except Exception: + traceback.print_exc() + + @classmethod + def _DragLeave(cls): + for self in cls.__subscribers.values(): + try: + self.DragLeave() # noqa + except Exception: + traceback.print_exc() + + @classmethod + def _Drop(cls, dataObject, keyState): + for self in cls.__subscribers.values(): + try: + self.Drop(dataObject, keyState) # noqa + except Exception: + traceback.print_exc() + + +class _DragAndDropForFunctions(DragAndDrop): + def DragEnter(self, dataObject, keyState): + ... + + def DragOver(self, keyState): + ... + + def DragLeave(self): + ... + + def Drop(self, dataObject, keyState): + ... + + +def set_drag_enter(function: Callable[[DragAndDropDataObject, list[KEYSTATE]], Any] = None): + if function is None: + function = lambda *args, **kwargs: ... + _DragAndDropForFunctions.DragEnter = function + + +def set_drag_over(function: Callable[[list[KEYSTATE]], Any] = None): + if function is None: + function = lambda *args, **kwargs: ... + _DragAndDropForFunctions.DragOver = function + + +def set_drag_leave(function: Callable[[], Any] = None): + if function is None: + function = lambda *args, **kwargs: ... + _DragAndDropForFunctions.DragLeave = function + + +def set_drop(function: Callable[[DragAndDropDataObject, list[KEYSTATE]], Any] = None): + if function is None: + function = lambda *args, **kwargs: ... + _DragAndDropForFunctions.Drop = function diff --git a/DearPyGui_DragAndDrop/setup.py b/DearPyGui_DragAndDrop/setup.py new file mode 100644 index 0000000..da938bc --- /dev/null +++ b/DearPyGui_DragAndDrop/setup.py @@ -0,0 +1,64 @@ +import ctypes +import os +import time + +import dearpygui.dearpygui as dpg +import pythoncom +import win32gui +from win32com.server.policy import DesignatedWrapPolicy + +from . import tools +from .main import DragAndDrop +from .main import get_drop_effect + +hwnd = -1 + + +class DropTarget(DesignatedWrapPolicy): + _public_methods_ = ['DragEnter', 'DragOver', 'DragLeave', 'Drop'] + _com_interfaces_ = [pythoncom.IID_IDropTarget] # noqa + + def __init__(self): # noqa + self._wrap_(self) + + def DragEnter(self, dataObject, keyState, point, effect): + ctypes.windll.user32.SetForegroundWindow(hwnd) + DragAndDrop._DragEnter(tools.get_data_from_dataObject(dataObject), + tools.key_state_to_keys_list(keyState)) + return 0, get_drop_effect() + # return winerror.S_OK, get_drop_effect() + + def DragOver(self, keyState, point, effect): + DragAndDrop._DragOver(tools.key_state_to_keys_list(keyState)) + return get_drop_effect() + + def DragLeave(self): + DragAndDrop._DragLeave() + + def Drop(self, dataObject, keyState, point, effect): + DragAndDrop._Drop(tools.get_data_from_dataObject(dataObject), + tools.key_state_to_keys_list(keyState)) + + +def setup(): + global hwnd + if hwnd != -1: + return + hwnd = 0 + # Wait for initialization and appearance of the DPG window + while dpg.get_frame_count() == 0: + time.sleep(0.1) + + # Get the window hwnd from its own pid + hwnd = tools.get_hwnd_from_pid(os.getpid()) + + pythoncom.OleInitialize() # noqa + pythoncom.RegisterDragDrop( # noqa + hwnd, + pythoncom.WrapObject( # noqa + DropTarget(), + pythoncom.IID_IDropTarget, # noqa + pythoncom.IID_IDropTarget # noqa + ) + ) + win32gui.PumpMessages() diff --git a/DearPyGui_DragAndDrop/tools.py b/DearPyGui_DragAndDrop/tools.py new file mode 100644 index 0000000..1430373 --- /dev/null +++ b/DearPyGui_DragAndDrop/tools.py @@ -0,0 +1,87 @@ +from __future__ import annotations + +import ctypes.wintypes +from ctypes import wintypes + +import pythoncom +import pywintypes +import win32con +from win32comext.shell import shell + +from .main import DragAndDropDataObject +from .main import KEYSTATE + + +def get_data_from_dataObject(dataObject) -> DragAndDropDataObject: + try: + # Drag&Drop files + _format = win32con.CF_HDROP, None, 1, -1, pythoncom.TYMED_HGLOBAL # noqa + sm = dataObject.GetData(_format) + except pywintypes.com_error: # noqa + try: + # Drag&Drop text + _format = win32con.CF_TEXT, None, 1, -1, pythoncom.TYMED_HGLOBAL # noqa + sm = dataObject.GetData(_format) + # returns a string converted from bytes + return sm.data.decode("utf-8") + except pywintypes.com_error: # noqa + # Drag&Drop unknown type + # return nothing + return None + + # Drag&Drop files + num_files = shell.DragQueryFile(sm.data_handle, -1) + files = [] + for i in range(num_files): + fpath = shell.DragQueryFile(sm.data_handle, i) + files.append(fpath) + # returns a list of file paths + return files + + +user32 = ctypes.windll.user32 +WNDENUMPROC = ctypes.WINFUNCTYPE(wintypes.BOOL, + wintypes.HWND, + wintypes.LPARAM) +user32.EnumWindows.argtypes = [WNDENUMPROC, + wintypes.LPARAM] + + +def get_hwnd_from_pid(pid: int) -> int | None: + result = None + + def callback(hwnd, _): + nonlocal result + lpdw_PID = ctypes.c_ulong() + user32.GetWindowThreadProcessId(hwnd, ctypes.byref(lpdw_PID)) + hwnd_PID = lpdw_PID.value + + if hwnd_PID == pid: + result = hwnd + return False + return True + + cb_worker = WNDENUMPROC(callback) + user32.EnumWindows(cb_worker, 0) + return result + + +def key_state_to_keys_list(keyState: int) -> list[KEYSTATE]: + # https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.drageventargs.keystate?view=windowsdesktop-7.0#remarks + key_state_list = [] + + # conversion to byte string and reverse it + keyState = '{0:06b}'.format(keyState)[::-1] + if bool(int(keyState[0])): + key_state_list.append(KEYSTATE.LEFT) + if bool(int(keyState[1])): + key_state_list.append(KEYSTATE.RIGHT) + if bool(int(keyState[2])): + key_state_list.append(KEYSTATE.SHIFT) + if bool(int(keyState[3])): + key_state_list.append(KEYSTATE.CTRL) + if bool(int(keyState[4])): + key_state_list.append(KEYSTATE.MIDDLE) + if bool(int(keyState[5])): + key_state_list.append(KEYSTATE.ALT) + return key_state_list diff --git a/Examples/EADME.md b/Examples/EADME.md new file mode 100644 index 0000000..857bbae --- /dev/null +++ b/Examples/EADME.md @@ -0,0 +1,50 @@ +# Examples + +You can find several scenarios here, from simple to advanced, for using the library.
+Below you can see what they look like and their brief description. + +## [Example №1: the simplest use case](example1.py) + +Probably the simplest and most used example of using. +Drop the file into the program and our `drop` (change text) function will be called. +![example_1](https://user-images.githubusercontent.com/46572469/210179706-f187b70b-6649-44d4-880b-a6b35a961d08.gif) + +## [Example №2: little interactivity](example2.py) + +An example with a little interactivity, in the form of a pop-up window that says `Drop!` +(This is "similar" to the popup in Discord when you try to send a file by drag and drop). +This one has more functions, but also seems to be nothing complicated. +In `drag_enter` and `drag_leave` we hide and show the window respectively, and in `drop` we add hiding the window. +![example_2](https://user-images.githubusercontent.com/46572469/210180323-1ab73614-0f35-49e8-b5e1-7c65c332e44b.gif) + +## [Example №3: more interactivity!](example3.py) + +In this example, you can only drop a file in the popup window. +Added a function `drag_over` which checks the pointing to the window and, depending on the result, +changes the theme of the window and the style of the cursor. +![example_3](https://user-images.githubusercontent.com/46572469/210180650-b91c77d8-19da-4452-ad69-f8caa0201c32.gif) + +## [Example №4: keys usage](example4.py) + +Let's expand our example again, now the window theme depends on the key presses (CTRL, ALT, SHIFT). +![example_4](https://user-images.githubusercontent.com/46572469/210181492-3a9bca4a-005a-4e5c-b8cf-4a39b041ef27.gif) + +## [Example №5: inheriting *DragAndDrop* or how to add an extra function to Drag And Drop](example4.py) + +Probably you need a lot of *DragAndDrop* functions when developing some applications, +and only one function can be attached to `set_drop`. +And there is a solution for this, namely to use the class *DragAndDrop*, or rather inherit it. +When `__init__` is called in *DragAndDrop* (`super().__init__()`), +this object (`self`) gets to the Drag-and-Drop functions queue, +where certain functions will be called in the future, for example `{DragAndDrop_oject}.DragOver`. +This example uses only `DragOver` and `Drop`, but also has `DragEnter` and `DragLeave` +which correspond to the functions `.set_drag_enter` and `.set_drag_leave` respectively. +I would also like to add that all functions `.set_*` are called first in the queue +(if you `.initialize()` before the DragAndDrop classes). +And the "function" of setting the cursor style will be called after the queue is finished +(that is, the last called `.set_drop_effect` will be taken).
+ +A little about the example: there are several "areas" in +which you can drop a file and the text in them will change when it `drop` + +![example_5](https://user-images.githubusercontent.com/46572469/210182508-d2232d43-0df3-4531-a34b-e773f9000ef9.gif) diff --git a/Examples/example1.py b/Examples/example1.py new file mode 100644 index 0000000..c14aa0e --- /dev/null +++ b/Examples/example1.py @@ -0,0 +1,25 @@ +import dearpygui.dearpygui as dpg + +import DearPyGui_DragAndDrop as dpg_dnd + +dpg.create_context() +dpg_dnd.initialize() +dpg.create_viewport(title="Drag and drop example1", width=600, height=600) + +with dpg.window() as window: + drop_text = dpg.add_text() + drop_keys = dpg.add_text() +dpg.set_primary_window(window, True) + + +def drop(data, keys): + dpg.set_value(drop_text, f'{data}') + dpg.set_value(drop_keys, f'{keys}') + + +dpg_dnd.set_drop(drop) + +dpg.setup_dearpygui() +dpg.show_viewport() +dpg.start_dearpygui() +dpg.destroy_context() diff --git a/Examples/example2.py b/Examples/example2.py new file mode 100644 index 0000000..7816eaa --- /dev/null +++ b/Examples/example2.py @@ -0,0 +1,39 @@ +import dearpygui.dearpygui as dpg + +import DearPyGui_DragAndDrop as dpg_dnd + +dpg.create_context() +dpg_dnd.initialize() +dpg.create_viewport(title="Drag and drop example2", width=600, height=600) + +with dpg.window() as window: + drop_text = dpg.add_text() + drop_keys = dpg.add_text() +dpg.set_primary_window(window, True) + +with dpg.window(modal=True, autosize=True, show=False) as drop_window: + dpg.add_text("Drop!", color=(0, 255, 0)) + + +def drop(data, keys): + dpg.configure_item(drop_window, show=False) + dpg.set_value(drop_text, f'{data}') + dpg.set_value(drop_keys, f'{keys}') + + +def drag_enter(data, keys): + dpg.configure_item(drop_window, show=True) + + +def drag_leave(): + dpg.configure_item(drop_window, show=False) + + +dpg_dnd.set_drop(drop) +dpg_dnd.set_drag_enter(drag_enter) +dpg_dnd.set_drag_leave(drag_leave) + +dpg.setup_dearpygui() +dpg.show_viewport() +dpg.start_dearpygui() +dpg.destroy_context() diff --git a/Examples/example3.py b/Examples/example3.py new file mode 100644 index 0000000..a28a422 --- /dev/null +++ b/Examples/example3.py @@ -0,0 +1,58 @@ +import dearpygui.dearpygui as dpg + +import DearPyGui_DragAndDrop as dpg_dnd + +dpg.create_context() +dpg_dnd.initialize() +dpg.create_viewport(title="Drag and drop example3", width=600, height=600) + +with dpg.theme() as hover_drag_theme: + with dpg.theme_component(dpg.mvAll): + dpg.add_theme_color(dpg.mvThemeCol_Border, (0, 180, 255), category=dpg.mvThemeCat_Core) + dpg.add_theme_color(dpg.mvThemeCol_PopupBg, (25, 50, 75), category=dpg.mvThemeCat_Core) + +with dpg.window() as window: + drop_text = dpg.add_text() + drop_keys = dpg.add_text() +dpg.set_primary_window(window, True) + +with dpg.window(modal=True, autosize=True, show=False) as drop_window: + dpg.add_text("Drop here!", color=(0, 255, 0)) + + +def drop(data, keys): + dpg.configure_item(drop_window, show=False) + dpg.bind_item_theme(drop_window, None) + dpg_dnd.set_drop_effect() + + dpg.set_value(drop_text, f'{data}') + dpg.set_value(drop_keys, f'{keys}') + + +def drag_over(keys): + if dpg.is_item_hovered(drop_window): + dpg.bind_item_theme(drop_window, hover_drag_theme) + dpg_dnd.set_drop_effect(dpg_dnd.DROPEFFECT.MOVE) + else: + dpg.bind_item_theme(drop_window, None) + dpg_dnd.set_drop_effect() + + +def drag_enter(data, keys): + dpg.configure_item(drop_window, show=True) + + +def drag_leave(): + dpg.configure_item(drop_window, show=False) + dpg.bind_item_theme(drop_window, None) + + +dpg_dnd.set_drop(drop) +dpg_dnd.set_drag_over(drag_over) +dpg_dnd.set_drag_enter(drag_enter) +dpg_dnd.set_drag_leave(drag_leave) + +dpg.setup_dearpygui() +dpg.show_viewport() +dpg.start_dearpygui() +dpg.destroy_context() diff --git a/Examples/example4.py b/Examples/example4.py new file mode 100644 index 0000000..fc619d0 --- /dev/null +++ b/Examples/example4.py @@ -0,0 +1,80 @@ +import dearpygui.dearpygui as dpg + +import DearPyGui_DragAndDrop as dpg_dnd + +dpg.create_context() +dpg_dnd.initialize() +dpg.create_viewport(title="Drag and drop example4", width=600, height=600) + +with dpg.theme() as hover_drag_theme_1: + with dpg.theme_component(dpg.mvAll): + dpg.add_theme_color(dpg.mvThemeCol_Border, (0, 180, 255), category=dpg.mvThemeCat_Core) + dpg.add_theme_color(dpg.mvThemeCol_PopupBg, (25, 50, 75), category=dpg.mvThemeCat_Core) +with dpg.theme() as hover_drag_theme_2: + with dpg.theme_component(dpg.mvAll): + dpg.add_theme_color(dpg.mvThemeCol_Border, (250, 5, 60), category=dpg.mvThemeCat_Core) + dpg.add_theme_color(dpg.mvThemeCol_PopupBg, (45, 15, 5), category=dpg.mvThemeCat_Core) +with dpg.theme() as hover_drag_theme_3: + with dpg.theme_component(dpg.mvAll): + dpg.add_theme_color(dpg.mvThemeCol_Border, (205, 0, 255), category=dpg.mvThemeCat_Core) + dpg.add_theme_color(dpg.mvThemeCol_PopupBg, (65, 30, 100), category=dpg.mvThemeCat_Core) +with dpg.theme() as hover_drag_theme_4: + with dpg.theme_component(dpg.mvAll): + dpg.add_theme_color(dpg.mvThemeCol_Border, (0, 255, 60), category=dpg.mvThemeCat_Core) + dpg.add_theme_color(dpg.mvThemeCol_PopupBg, (30, 65, 30), category=dpg.mvThemeCat_Core) + +with dpg.window() as window: + drop_text = dpg.add_text() + drop_keys = dpg.add_text() +dpg.set_primary_window(window, True) + +with dpg.window(modal=True, autosize=True, show=False) as drop_window: + dpg.add_text("Drop here!", color=(0, 255, 0)) + + +def drop(data, keys): + dpg.configure_item(drop_window, show=False) + dpg.bind_item_theme(drop_window, None) + dpg_dnd.set_drop_effect() + + dpg.set_value(drop_text, f'{data}') + dpg.set_value(drop_keys, f'{keys}') + + +def drag_over(keys): + if not dpg.is_item_hovered(drop_window): + dpg.bind_item_theme(drop_window, None) + dpg_dnd.set_drop_effect() + return + + hover_drag_theme = hover_drag_theme_1 + if dpg_dnd.KEYSTATE.ALT in keys and dpg_dnd.KEYSTATE.CTRL in keys: + hover_drag_theme = hover_drag_theme_2 + elif dpg_dnd.KEYSTATE.ALT in keys: + hover_drag_theme = hover_drag_theme_3 + elif dpg_dnd.KEYSTATE.CTRL in keys: + hover_drag_theme = hover_drag_theme_4 + + dpg.bind_item_theme(drop_window, hover_drag_theme) + dpg_dnd.set_drop_effect(dpg_dnd.DROPEFFECT.MOVE) + + +def drag_enter(data, keys): + dpg.configure_item(drop_window, show=True) + + +def drag_leave(): + dpg.configure_item(drop_window, show=False) + dpg.bind_item_theme(drop_window, None) + dpg_dnd.set_drop_effect() + + +dpg_dnd.set_drop(drop) +dpg_dnd.set_drag_over(drag_over) +dpg_dnd.set_drag_enter(drag_enter) +dpg_dnd.set_drag_leave(drag_leave) + +dpg.setup_dearpygui() +dpg.show_viewport() +dpg.start_dearpygui() +dpg.destroy_context() diff --git a/Examples/example5.py b/Examples/example5.py new file mode 100644 index 0000000..18c1b64 --- /dev/null +++ b/Examples/example5.py @@ -0,0 +1,59 @@ +import dearpygui.dearpygui as dpg + +import DearPyGui_DragAndDrop as dpg_dnd + +dpg.create_context() +dpg_dnd.initialize() +dpg.create_viewport(title="Drag and drop example5", width=600, height=600) + +with dpg.theme() as hover_drag_theme: + with dpg.theme_component(dpg.mvAll): + dpg.add_theme_color(dpg.mvThemeCol_Border, (0, 180, 255), category=dpg.mvThemeCat_Core) + dpg.add_theme_color(dpg.mvThemeCol_ChildBg, (25, 50, 75), category=dpg.mvThemeCat_Core) + + +class ChildWindow(dpg_dnd.DragAndDrop): + window: int = None + dpg_text: int + + def __init__(self): + super().__init__() + + def create(self): + with dpg.child_window(width=-1, height=50) as self.window: + self.dpg_text = dpg.add_text(parent=self.window) + + def DragOver(self, keyState: list[dpg_dnd.KEYSTATE]): + if self.window is None: + return + if dpg.is_item_hovered(self.window): + dpg.bind_item_theme(self.window, hover_drag_theme) + dpg_dnd.set_drop_effect(dpg_dnd.DROPEFFECT.MOVE) + else: + dpg.bind_item_theme(self.window, None) + + def Drop(self, dataObject: dpg_dnd.DragAndDropDataObject, keyState: list[dpg_dnd.KEYSTATE]): + if self.window is None: + return + dpg.bind_item_theme(self.window, None) + if dpg.is_item_hovered(self.window): + dpg.set_value(self.dpg_text, f'{dataObject}') + +def drag_over(keys): + dpg_dnd.set_drop_effect() + + +dpg_dnd.set_drag_over(drag_over) + +with dpg.window() as window: + for i in range(5): + child_window = ChildWindow() + child_window.create() + dpg.add_spacer(height=25) + +dpg.set_primary_window(window, True) + +dpg.setup_dearpygui() +dpg.show_viewport() +dpg.start_dearpygui() +dpg.destroy_context() diff --git a/README.md b/README.md new file mode 100644 index 0000000..a9e403d --- /dev/null +++ b/README.md @@ -0,0 +1,60 @@ +# DearPyGui-DragAndDrop + +Working Drag-and-drop for DearPyGui, Windows only +![demo](https://user-images.githubusercontent.com/46572469/210178591-3011e753-82ed-4d8f-8652-87375d7366e0.gif) + +## How to install/use + +1) Install the DearPyGui-DragAndDrop package:
+ `pip install DearPyGui-DragAndDrop` + +2) Import and then initialize the library after `dpg.create_context()`: + +```python +import dearpygui.dearpygui as dpg + +import DearPyGui_DragAndDrop as dpg_dnd + +dpg.create_context() +dpg_dnd.initialize() +``` + +3) That's it, just set your function for `drop` and your minimal use case is ready: + +```python +import dearpygui.dearpygui as dpg + +import DearPyGui_DragAndDrop as dpg_dnd + +dpg.create_context() +dpg_dnd.initialize() +dpg.create_viewport(title="Drag and drop example", width=600, height=600) + + +def drop(data, keys): + print(f'{data}') + print(f'{keys}') + + +dpg_dnd.set_drop(drop) + +dpg.setup_dearpygui() +dpg.show_viewport() +dpg.start_dearpygui() +dpg.destroy_context() +``` + +### More examples of use are in the [Examples folder](https://github.com/IvanNazaruk/DearPyGui-DragAndDrop/Examples) + +## Supported Formats + +- [x] File(s) paths *(will be in the form of a `list of strings`)* +- [x] Text *(will be `string`)* + +Everything else will be `None` or will be a `string` + +## TODO list: + +- [ ] Documentation and code/functions comments +- [ ] Add support for more and other data + types: [maybe this is the right list](https://learn.microsoft.com/en-us/windows/win32/dataxchg/standard-clipboard-formats#constants) \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..644b6d9 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,31 @@ +[build-system] +requires = ["setuptools>=61.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "DearPyGui-DragAndDrop" +version = "1.0.0" +authors = [ + { name = "Ivan Nazaruk" }, +] +description = "Working Drag-and-Drop for DearPyGui, Windows only" +readme = "README.md" +requires-python = ">=3.7" +license = { text = "MIT" } +classifiers = [ + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Operating System :: Microsoft :: Windows" +] +dependencies = [ + "pywin32", + "dearpygui>=1.4" +] + +[tool.setuptools] +packages = ["DearPyGui_DragAndDrop"] + +[project.urls] +"Homepage" = "https://github.com/IvanNazaruk/DearPyGui-DragAndDrop" +"Bug Tracker" = "https://github.com/IvanNazaruk/DearPyGui-DragAndDrop/issues" \ No newline at end of file