diff --git a/.gitignore b/.gitignore index 641a484..a9aba72 100644 --- a/.gitignore +++ b/.gitignore @@ -248,3 +248,5 @@ test_results/ # Keep docs/*.md and tests fixtures tracked; only ignore root-level files /AGENTS.md /*.txt +!CubeMain.txt +!CubeMainWorking.txt diff --git a/CubeMain.txt b/CubeMain.txt new file mode 100644 index 0000000..0a735b3 --- /dev/null +++ b/CubeMain.txt @@ -0,0 +1,2 @@ +col1 col2 +1 2 diff --git a/CubeMainWorking.txt b/CubeMainWorking.txt new file mode 100644 index 0000000..0a735b3 --- /dev/null +++ b/CubeMainWorking.txt @@ -0,0 +1,2 @@ +col1 col2 +1 2 diff --git a/README.md b/README.md index ab95823..63c5fa4 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ Diablo2TextEditor/ - **UI Editor**: Full-featured graphical interface for editing game data - **Format Validation**: Comprehensive file format verification - **PDF Extraction**: Tools for extracting data from PDF documentation +- **Drag-and-Drop Loading**: Open any supported `.txt` file by simply dropping it onto the editor window ## Installation diff --git a/file_bindings.py b/file_bindings.py index d1acc9a..cda7147 100644 --- a/file_bindings.py +++ b/file_bindings.py @@ -17,7 +17,8 @@ class DataFileBinding: def __init__(self, json_path: str, txt_path: str = None, metadata: Dict = None): self.json_path = json_path - self.txt_path = txt_path + # Use an empty string for unbound txt paths so os.path functions don't error. + self.txt_path = txt_path or "" self.metadata = metadata or {} self.base_name = Path(json_path).stem @@ -33,7 +34,7 @@ def load_metadata(self) -> Dict: def load_data(self): """Load the actual data from the .txt file.""" - if self.txt_path is None: + if not self.txt_path: raise ValueError("No txt file path set for this binding. Use create_dynamic_binding() first.") return open_txt_file(self.txt_path) diff --git a/ui.py b/ui.py index 9825426..d0049f9 100644 --- a/ui.py +++ b/ui.py @@ -662,25 +662,25 @@ def _load_file_path(self, file_path: str): # Drag-and-drop support def dragEnterEvent(self, event): + """Allow drag if payload contains at least one local .txt file.""" if event.mimeData().hasUrls(): - # Accept if any of the URLs is a .txt file - for url in event.mimeData().urls(): - if url.isLocalFile() and url.toLocalFile().lower().endswith('.txt'): - event.acceptProposedAction() - return + urls = event.mimeData().urls() + if any(u.isLocalFile() and u.toLocalFile().lower().endswith(".txt") for u in urls): + event.acceptProposedAction() + return event.ignore() + def dragMoveEvent(self, event): + """Continuously accept drags containing valid .txt files.""" + self.dragEnterEvent(event) + def dropEvent(self, event): - handled = False + """Open the first dropped .txt file.""" for url in event.mimeData().urls(): - local = url.toLocalFile() - if url.isLocalFile() and local.lower().endswith('.txt'): - self._load_file_path(local) - handled = True - # Load only first file for now + if url.isLocalFile() and url.toLocalFile().lower().endswith(".txt"): + self._load_file_path(url.toLocalFile()) + event.acceptProposedAction() break - if handled: - event.acceptProposedAction() else: event.ignore()