Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add options to disable copy & paste #585

Merged
merged 2 commits into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 20 additions & 7 deletions pygame_gui/core/utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@
stdout, _ = process.communicate()
return stdout.decode('utf-8')

else:
elif PLATFORM == 'DARWIN':
def __mac_copy(data: str):
with subprocess.Popen('pbcopy',
env={'LANG': 'en_US.UTF-8'},
Expand All @@ -185,43 +185,56 @@
return subprocess.check_output(
'pbpaste', env={'LANG': 'en_US.UTF-8'}).decode('utf-8')

else:
def __unknown_copy(data: str):

Check warning on line 189 in pygame_gui/core/utility.py

View check run for this annotation

Codecov / codecov/patch

pygame_gui/core/utility.py#L189

Added line #L189 was not covered by tests
# copy not supported on this platform
pass

Check warning on line 191 in pygame_gui/core/utility.py

View check run for this annotation

Codecov / codecov/patch

pygame_gui/core/utility.py#L191

Added line #L191 was not covered by tests

def __unknown_paste():

Check warning on line 193 in pygame_gui/core/utility.py

View check run for this annotation

Codecov / codecov/patch

pygame_gui/core/utility.py#L193

Added line #L193 was not covered by tests
# paste not supported on this platform
return ""

Check warning on line 195 in pygame_gui/core/utility.py

View check run for this annotation

Codecov / codecov/patch

pygame_gui/core/utility.py#L195

Added line #L195 was not covered by tests


def clipboard_copy(data: str):
"""
Hopefully cross platform, copy to a clipboard.
Hopefully cross-platform, copy to a clipboard.

:return: A platform specific copy function.

"""
if pygame.vernum.major == 2 and pygame.vernum.minor >= 2:
if (pygame.vernum.major == 2 and pygame.vernum.minor >= 2) or pygame.vernum.major > 2:
pygame.scrap.put_text(data)
else:
current_platform = platform.system().upper()
if current_platform == 'WINDOWS':
__windows_copy(data)
elif current_platform == 'LINUX':
__linux_copy(data)
else:
elif current_platform == 'DARWIN':

Check warning on line 213 in pygame_gui/core/utility.py

View check run for this annotation

Codecov / codecov/patch

pygame_gui/core/utility.py#L213

Added line #L213 was not covered by tests
__mac_copy(data)
else:
__unknown_copy(data)

Check warning on line 216 in pygame_gui/core/utility.py

View check run for this annotation

Codecov / codecov/patch

pygame_gui/core/utility.py#L216

Added line #L216 was not covered by tests


def clipboard_paste():
"""
Hopefully cross platform, paste from a clipboard.
Hopefully cross-platform, paste from a clipboard.

:return: A platform specific paste function.

"""
if pygame.vernum.major == 2 and pygame.vernum.minor >= 2:
if (pygame.vernum.major == 2 and pygame.vernum.minor >= 2) or pygame.vernum.major > 2:
return pygame.scrap.get_text()
else:
current_platform = platform.system().upper()
if current_platform == 'WINDOWS':
return __windows_paste()
elif current_platform == 'LINUX':
return __linux_paste()
else:
elif current_platform == 'DARWIN':

Check warning on line 234 in pygame_gui/core/utility.py

View check run for this annotation

Codecov / codecov/patch

pygame_gui/core/utility.py#L234

Added line #L234 was not covered by tests
return __mac_paste()
else:
return __unknown_paste()

Check warning on line 237 in pygame_gui/core/utility.py

View check run for this annotation

Codecov / codecov/patch

pygame_gui/core/utility.py#L237

Added line #L237 was not covered by tests


def create_resource_path(relative_path: Union[str, Path]):
Expand Down
6 changes: 5 additions & 1 deletion pygame_gui/elements/ui_text_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@ def __init__(self,
self.vertical_cursor_movement = False
self.last_horiz_cursor_index = 0

self.copy_text_enabled = True
self.paste_text_enabled = False

self.rebuild_from_changed_theme_data()

@property
Expand Down Expand Up @@ -922,7 +925,8 @@ def _do_copy(self):
if self.text_box_layout is not None and abs(self.select_range[0] - self.select_range[1]) > 0:
low_end = min(self.select_range[0], self.select_range[1])
high_end = max(self.select_range[0], self.select_range[1])
clipboard_copy(self.text_box_layout.plain_text[low_end:high_end])
if self.ui_manager.copy_text_enabled and self.copy_text_enabled:
clipboard_copy(self.text_box_layout.plain_text[low_end:high_end])

def _calculate_double_click_word_selection(self):
"""
Expand Down
72 changes: 38 additions & 34 deletions pygame_gui/elements/ui_text_entry_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ def __init__(self,
self.cursor_blink_delay_after_moving = 1.0
self.blink_cursor_time_acc = 0.0
self.blink_cursor_time = 0.4
self.paste_text_enabled = True

self.cursor_on = False

Expand Down Expand Up @@ -333,17 +334,19 @@ def _process_cut_event(self, event: Event) -> bool:
return consumed_event

def _do_cut(self):
if abs(self.select_range[0] - self.select_range[1]) > 0:
low_end = min(self.select_range[0], self.select_range[1])
high_end = max(self.select_range[0], self.select_range[1])
clipboard_copy(self.html_text[low_end:high_end])
self.text_box_layout.delete_selected_text()
self.edit_position = low_end
self.html_text = self.html_text[:low_end] + self.html_text[high_end:]
self.text_box_layout.set_cursor_position(self.edit_position)
self.select_range = [0, 0]
self.redraw_from_text_block()
self.cursor_has_moved_recently = True
if self.ui_manager.copy_text_enabled and self.copy_text_enabled:
if abs(self.select_range[0] - self.select_range[1]) > 0:
low_end = min(self.select_range[0], self.select_range[1])
high_end = max(self.select_range[0], self.select_range[1])

clipboard_copy(self.html_text[low_end:high_end])
self.text_box_layout.delete_selected_text()
self.edit_position = low_end
self.html_text = self.html_text[:low_end] + self.html_text[high_end:]
self.text_box_layout.set_cursor_position(self.edit_position)
self.select_range = [0, 0]
self.redraw_from_text_block()
self.cursor_has_moved_recently = True

def _process_paste_event(self, event: Event) -> bool:
"""
Expand All @@ -362,30 +365,31 @@ def _process_paste_event(self, event: Event) -> bool:
return consumed_event

def _do_paste(self):
paste = clipboard_paste()
if paste is not None:
new_text = self.convert_all_line_endings_to_unix(clipboard_paste())
if self.ui_manager.paste_text_enabled and self.paste_text_enabled:
paste = clipboard_paste()
if paste is not None:
new_text = self.convert_all_line_endings_to_unix(clipboard_paste())

if abs(self.select_range[0] - self.select_range[1]) > 0:
low_end = min(self.select_range[0], self.select_range[1])
high_end = max(self.select_range[0], self.select_range[1])
self.html_text = self.html_text[:low_end] + new_text + self.html_text[high_end:]
self.set_text(self.html_text)
self.edit_position = low_end + len(new_text)
self.text_box_layout.set_cursor_position(self.edit_position)
self.redraw_from_text_block()
self.select_range = [0, 0]
self.cursor_has_moved_recently = True
elif len(new_text) > 0:
self.html_text = (self.html_text[:self.edit_position] +
new_text +
self.html_text[self.edit_position:])
original_edit_pos = self.edit_position
self.set_text(self.html_text)
self.edit_position = original_edit_pos + len(new_text)
self.text_box_layout.set_cursor_position(self.edit_position)
self.redraw_from_text_block()
self.cursor_has_moved_recently = True
if abs(self.select_range[0] - self.select_range[1]) > 0:
low_end = min(self.select_range[0], self.select_range[1])
high_end = max(self.select_range[0], self.select_range[1])
self.html_text = self.html_text[:low_end] + new_text + self.html_text[high_end:]
self.set_text(self.html_text)
self.edit_position = low_end + len(new_text)
self.text_box_layout.set_cursor_position(self.edit_position)
self.redraw_from_text_block()
self.select_range = [0, 0]
self.cursor_has_moved_recently = True
elif len(new_text) > 0:
self.html_text = (self.html_text[:self.edit_position] +
new_text +
self.html_text[self.edit_position:])
original_edit_pos = self.edit_position
self.set_text(self.html_text)
self.edit_position = original_edit_pos + len(new_text)
self.text_box_layout.set_cursor_position(self.edit_position)
self.redraw_from_text_block()
self.cursor_has_moved_recently = True

def redraw_from_text_block(self):
self.text_box_layout.fit_layout_rect_height_to_rows()
Expand Down
128 changes: 67 additions & 61 deletions pygame_gui/elements/ui_text_entry_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ def __init__(self,
self.forbidden_characters: Optional[List[str]] = None
self.length_limit: Optional[int] = None

self.copy_text_enabled = True
self.paste_text_enabled = True

self.rebuild_from_changed_theme_data()

@property
Expand Down Expand Up @@ -780,20 +783,21 @@ def _process_cut_event(self, event: Event) -> bool:
return consumed_event

def _do_cut(self):
if abs(self.select_range[0] - self.select_range[1]) > 0:
low_end = min(self.select_range[0], self.select_range[1])
high_end = max(self.select_range[0], self.select_range[1])
clipboard_copy(self.text[low_end:high_end])
if self.drawable_shape is not None:
self.drawable_shape.text_box_layout.delete_selected_text()
self.drawable_shape.apply_active_text_changes()
self.edit_position = low_end
self.text = self.text[:low_end] + self.text[high_end:]
if self.drawable_shape is not None:
self.drawable_shape.text_box_layout.set_cursor_position(self.edit_position)
self.drawable_shape.apply_active_text_changes()
self.select_range = [0, 0]
self.cursor_has_moved_recently = True
if self.ui_manager.copy_text_enabled and self.copy_text_enabled:
if abs(self.select_range[0] - self.select_range[1]) > 0:
low_end = min(self.select_range[0], self.select_range[1])
high_end = max(self.select_range[0], self.select_range[1])
clipboard_copy(self.text[low_end:high_end])
if self.drawable_shape is not None:
self.drawable_shape.text_box_layout.delete_selected_text()
self.drawable_shape.apply_active_text_changes()
self.edit_position = low_end
self.text = self.text[:low_end] + self.text[high_end:]
if self.drawable_shape is not None:
self.drawable_shape.text_box_layout.set_cursor_position(self.edit_position)
self.drawable_shape.apply_active_text_changes()
self.select_range = [0, 0]
self.cursor_has_moved_recently = True

def _process_copy_event(self, event: Event) -> bool:
"""
Expand All @@ -817,7 +821,8 @@ def _do_copy(self):
if abs(self.select_range[0] - self.select_range[1]) > 0:
low_end = min(self.select_range[0], self.select_range[1])
high_end = max(self.select_range[0], self.select_range[1])
clipboard_copy(self.text[low_end:high_end])
if self.ui_manager.copy_text_enabled and self.copy_text_enabled:
clipboard_copy(self.text[low_end:high_end])

def _process_paste_event(self, event: pygame.event.Event) -> bool:
"""
Expand All @@ -837,52 +842,53 @@ def _process_paste_event(self, event: pygame.event.Event) -> bool:
return consumed_event

def _do_paste(self):
new_text = clipboard_paste()
if self.validate_text_string(new_text):
if abs(self.select_range[0] - self.select_range[1]) > 0:
low_end = min(self.select_range[0], self.select_range[1])
high_end = max(self.select_range[0], self.select_range[1])
final_text = self.text[:low_end] + new_text + self.text[high_end:]
within_length_limit = True
if self.length_limit is not None and len(final_text) > self.length_limit:
within_length_limit = False
if within_length_limit:
self.text = final_text
if self.drawable_shape is not None:
self.drawable_shape.text_box_layout.delete_selected_text()
self.drawable_shape.apply_active_text_changes()
display_new_text = new_text
if self.is_text_hidden:
display_new_text = self.hidden_text_char * len(new_text)
if self.drawable_shape is not None:
self.drawable_shape.insert_text(display_new_text, low_end)
self.edit_position = low_end + len(new_text)
if self.drawable_shape is not None:
self.drawable_shape.text_box_layout.set_cursor_position(
self.edit_position)
self.drawable_shape.apply_active_text_changes()
self.select_range = [0, 0]
self.cursor_has_moved_recently = True
elif len(new_text) > 0:
final_text = (self.text[:self.edit_position] +
new_text +
self.text[self.edit_position:])
within_length_limit = True
if self.length_limit is not None and len(final_text) > self.length_limit:
within_length_limit = False
if within_length_limit:
self.text = final_text
display_new_text = new_text
if self.is_text_hidden:
display_new_text = self.hidden_text_char * len(new_text)
if self.drawable_shape is not None:
self.drawable_shape.insert_text(display_new_text, self.edit_position)
self.edit_position += len(new_text)
if self.drawable_shape is not None:
self.drawable_shape.text_box_layout.set_cursor_position(
self.edit_position)
self.drawable_shape.apply_active_text_changes()
self.cursor_has_moved_recently = True
if self.ui_manager.paste_text_enabled and self.paste_text_enabled:
new_text = clipboard_paste()
if self.validate_text_string(new_text):
if abs(self.select_range[0] - self.select_range[1]) > 0:
low_end = min(self.select_range[0], self.select_range[1])
high_end = max(self.select_range[0], self.select_range[1])
final_text = self.text[:low_end] + new_text + self.text[high_end:]
within_length_limit = True
if self.length_limit is not None and len(final_text) > self.length_limit:
within_length_limit = False
if within_length_limit:
self.text = final_text
if self.drawable_shape is not None:
self.drawable_shape.text_box_layout.delete_selected_text()
self.drawable_shape.apply_active_text_changes()
display_new_text = new_text
if self.is_text_hidden:
display_new_text = self.hidden_text_char * len(new_text)
if self.drawable_shape is not None:
self.drawable_shape.insert_text(display_new_text, low_end)
self.edit_position = low_end + len(new_text)
if self.drawable_shape is not None:
self.drawable_shape.text_box_layout.set_cursor_position(
self.edit_position)
self.drawable_shape.apply_active_text_changes()
self.select_range = [0, 0]
self.cursor_has_moved_recently = True
elif len(new_text) > 0:
final_text = (self.text[:self.edit_position] +
new_text +
self.text[self.edit_position:])
within_length_limit = True
if self.length_limit is not None and len(final_text) > self.length_limit:
within_length_limit = False
if within_length_limit:
self.text = final_text
display_new_text = new_text
if self.is_text_hidden:
display_new_text = self.hidden_text_char * len(new_text)
if self.drawable_shape is not None:
self.drawable_shape.insert_text(display_new_text, self.edit_position)
self.edit_position += len(new_text)
if self.drawable_shape is not None:
self.drawable_shape.text_box_layout.set_cursor_position(
self.edit_position)
self.drawable_shape.apply_active_text_changes()
self.cursor_has_moved_recently = True

def _process_mouse_button_event(self, event: pygame.event.Event) -> bool:
"""
Expand Down
3 changes: 3 additions & 0 deletions pygame_gui/ui_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ def __init__(self,
self.text_hovered = False
self.hovering_any_ui_element = False

self.copy_text_enabled = True
self.paste_text_enabled = True

if auto_load:
self.resource_loader.start()
# If we are using a blocking loader this will only return when loading is complete
Expand Down
Loading