started work on right click menus
This commit is contained in:
		
							
								
								
									
										119
									
								
								context_menu.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								context_menu.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | ||||
| # totally not stolen from my code for my chat app Portal ;) | ||||
| from __future__ import annotations | ||||
| from textual.screen import ModalScreen | ||||
| from textual.containers import Container | ||||
| from textual.widgets import Static | ||||
| from textual.geometry import Offset | ||||
| from textual.message import Message | ||||
| from textual.visual import VisualType | ||||
| from textual import on, events | ||||
|  | ||||
|  | ||||
| class NoSelectStatic(Static): | ||||
| 	"""This class is used in window.py and windowbar.py to create buttons.""" | ||||
|  | ||||
| 	@property | ||||
| 	def allow_select(self) -> bool: | ||||
| 		return False | ||||
|  | ||||
|  | ||||
| class ButtonStatic(NoSelectStatic): | ||||
| 	"""This class is used in window.py, windowbar.py, and switcher.py to create buttons.""" | ||||
|  | ||||
| 	class Pressed(Message): | ||||
| 		def __init__(self, button: ButtonStatic) -> None: | ||||
| 			super().__init__() | ||||
| 			self.button = button | ||||
|  | ||||
| 		@property | ||||
| 		def control(self) -> ButtonStatic: | ||||
| 			return self.button | ||||
|  | ||||
| 	def __init__( | ||||
| 		self, | ||||
| 		content: VisualType = "", | ||||
| 		*, | ||||
| 		expand: bool = False, | ||||
| 		shrink: bool = False, | ||||
| 		markup: bool = True, | ||||
| 		name: str | None = None, | ||||
| 		id: str | None = None, | ||||
| 		classes: str | None = None, | ||||
| 		disabled: bool = False, | ||||
| 	) -> None: | ||||
| 		super().__init__( | ||||
| 			content=content, | ||||
| 			expand=expand, | ||||
| 			shrink=shrink, | ||||
| 			markup=markup, | ||||
| 			name=name, | ||||
| 			id=id, | ||||
| 			classes=classes, | ||||
| 			disabled=disabled, | ||||
| 		) | ||||
| 		self.click_started_on: bool = False | ||||
|  | ||||
| 	def on_mouse_down(self, event: events.MouseDown) -> None: | ||||
|  | ||||
| 		self.add_class("pressed") | ||||
| 		self.click_started_on = True | ||||
|  | ||||
| 	def on_mouse_up(self, event: events.MouseUp) -> None: | ||||
|  | ||||
| 		self.remove_class("pressed") | ||||
| 		if self.click_started_on: | ||||
| 			self.post_message(self.Pressed(self)) | ||||
| 			self.click_started_on = False | ||||
|  | ||||
| 	def on_leave(self, event: events.Leave) -> None: | ||||
|  | ||||
| 		self.remove_class("pressed") | ||||
| 		self.click_started_on = False | ||||
|  | ||||
|  | ||||
| class ContextMenu(ModalScreen): | ||||
| 	DEFAULT_CSS = """ | ||||
| 	ContextMenu { | ||||
| 		background: $background 0%; | ||||
| 		align: left top; | ||||
| 	} | ||||
|  | ||||
| 	#menu_container { | ||||
| 		padding: 0 1; | ||||
| 		background: $surface; | ||||
| 		width: 21; | ||||
| 		border: hkey $panel; | ||||
| 		& > ButtonStatic { | ||||
| 			content-align: left middle; | ||||
| 			&:hover { background: $panel-lighten-2; } | ||||
| 			&.pressed { background: $primary; }         | ||||
| 			 | ||||
| 		} | ||||
| 	} | ||||
| 	""" | ||||
|  | ||||
| 	def __init__(self, options: list[str], offset: Offset): | ||||
| 		super().__init__() | ||||
| 		self.options = options | ||||
| 		self.mouse_offset = offset | ||||
| 			 | ||||
| 	def on_mouse_up(self, event: events.MouseUp): | ||||
| 		if not self.query_one("#menu_container").region.contains(event.screen_x, event.screen_y): | ||||
| 			self.dismiss(None) | ||||
|  | ||||
| 	@on(ButtonStatic.Pressed) | ||||
| 	async def thingy(self, event: ButtonStatic.Pressed): | ||||
| 		self.dismiss(event.button.content) | ||||
|  | ||||
| 	def compose(self): | ||||
| 		with Container(id="menu_container"): | ||||
| 			for option in self.options: | ||||
| 				if isinstance(option, str): | ||||
| 					yield ButtonStatic(option) | ||||
| 				else: | ||||
| 					yield option | ||||
|  | ||||
| 	def on_mount(self): | ||||
| 		menu_container = self.query_one("#menu_container") | ||||
| 		menu_container.styles.height = len(menu_container.children) + 2 | ||||
| 		menu_container.offset = self.mouse_offset | ||||
							
								
								
									
										31
									
								
								directory_tree_custom.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								directory_tree_custom.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| from textual.widgets import DirectoryTree, Rule | ||||
| from textual.widgets.tree import TreeNode | ||||
| from textual.events import MouseDown | ||||
| from context_menu import ContextMenu, NoSelectStatic | ||||
|  | ||||
|  | ||||
| class CustomDirectoryTree(DirectoryTree): | ||||
| 	def __init__(self, path, *, name = None, id = None, classes = None, disabled = False): | ||||
| 		super().__init__(path, name=name, id=id, classes=classes, disabled=disabled) | ||||
| 		self.right_clicked_node: TreeNode | None = None | ||||
|  | ||||
| 	def context_menu_chosen(self, result): | ||||
| 		self.right_clicked_node = None | ||||
|  | ||||
| 	def on_mouse_down(self, event: MouseDown): | ||||
| 		if event.button != 3 or not "line" in event.style.meta: | ||||
| 			return | ||||
| 		selected_node = self.get_node_at_line(event.style.meta["line"]) | ||||
| 		self.right_clicked_node = selected_node | ||||
|  | ||||
| 		options = None | ||||
| 		if self._safe_is_dir(self.right_clicked_node.data.path): | ||||
| 			options = ["New Folder", "New File", NoSelectStatic(f'[d]{"-" * 17}[/]'), "Delete", "Rename", "Open"] | ||||
| 		else: | ||||
| 			options = ["Delete", "Rename", "Open"] | ||||
| 		 | ||||
| 		self.app.push_screen(ContextMenu( | ||||
| 			[NoSelectStatic(f"[b]{self.right_clicked_node.label}[/]"), NoSelectStatic(f'[d]{"-" * 17}[/]')] + options, | ||||
| 			event.screen_offset | ||||
| 		), self.context_menu_chosen) | ||||
|  | ||||
							
								
								
									
										4
									
								
								main.py
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								main.py
									
									
									
									
									
								
							| @@ -12,11 +12,11 @@ from assets.theme_mappings import theme_mappings | ||||
| from plugin_loader import PluginLoader | ||||
| from settings import SettingsScreen | ||||
| from settings_store import ConfigHandler | ||||
| from directory_tree_custom import CustomDirectoryTree | ||||
|  | ||||
| from watchdog.observers import Observer | ||||
| from watchdog.events import FileSystemEventHandler | ||||
|  | ||||
| import subprocess | ||||
| import os | ||||
|  | ||||
|  | ||||
| @@ -56,7 +56,7 @@ class Berry(App): | ||||
| 			with ContentSwitcher(initial="files", id="sidebar-switcher"): | ||||
| 				with Vertical(id="files"): | ||||
| 					yield Static("EXPLORER") | ||||
| 					yield DirectoryTree(self.path, id="directory") | ||||
| 					yield CustomDirectoryTree(self.path, id="directory") | ||||
|  | ||||
| 		with Vertical(id="editor"): | ||||
| 			first_tab = Tab("New File") | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 SpookyDervish
					SpookyDervish