Skip to content
Open
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
1 change: 1 addition & 0 deletions modules/callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ def popup_content():
start_dir /= best_match
utils.push_popup(filepicker.FilePicker(
title=f"Select or drop executable for {game.name}",
picker_type=filepicker.PickerType.Execs,
start_dir=start_dir,
callback=select_callback,
buttons=[use_uri]
Expand Down
1 change: 1 addition & 0 deletions modules/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ async def connect():
"style_corner_radius": f'INTEGER DEFAULT {DefaultStyle.corner_radius}',
"style_text": f'TEXT DEFAULT "{DefaultStyle.text}"',
"style_text_dim": f'TEXT DEFAULT "{DefaultStyle.text_dim}"',
"style_filepicker_highlight": f'TEXT DEFAULT "{DefaultStyle.filepicker_highlight}"',
"tags_highlights": f'TEXT DEFAULT "{{}}"',
"timestamp_format": f'TEXT DEFAULT "%d/%m/%Y %H:%M"',
"use_parser_processes": f'INTEGER DEFAULT {int(True)}',
Expand Down
118 changes: 87 additions & 31 deletions modules/filepicker.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# https://gist.github.com/Willy-JL/82137493896d385a74d148534691b6e1
from enum import Enum, auto
import pathlib
import typing
import string
Expand All @@ -14,13 +15,49 @@
utils, # added
) # added

dir_icon = f"{icons.folder_outline} " # changed
file_icon = f"{icons.file_outline} " # changed
dir_icon = f"{icons.folder}" # changed
file_icon = f"{icons.file_outline}" # changed
up_icon = icons.arrow_up # changed
refresh_icon = icons.refresh # changed
cancel_icon = f"{icons.cancel} Cancel" # changed
ok_icon = f"{icons.check} Ok" # changed

class PickerType(Enum):
Dirs = auto()
Execs = auto()
Media = auto()
Bookmarks = auto()

class ListItem:
def __init__(self, path: pathlib.Path, picker_type: PickerType | None):
self.path = path
self.name = path.name
self.ptype = picker_type
self.is_dir = path.is_dir()
self.is_file = path.is_file()
if self.is_dir:
self.icon = dir_icon
self.color = globals.settings.style_text
else:
self.icon, self.color = self.get_file_decorations()

def get_file_decorations(self) -> tuple[str, tuple[float, ...]]:
if (ext := self.path.suffix) and self.ptype:
if self.ptype == PickerType.Execs and ext in (".exe", ".sh", ".swf", ".html", ".jar"):
return icons.file_cog_outline, globals.settings.style_filepicker_highlight
if self.ptype == PickerType.Media and ext in (".png", ".jpg", ".jpeg", ".webp"):
return icons.image_outline, globals.settings.style_filepicker_highlight
if self.ptype == PickerType.Media and ext in (".gif"):
return icons.video_outline, globals.settings.style_filepicker_highlight
if self.ptype == PickerType.Bookmarks and ext == ".html":
return icons.star_outline, globals.settings.style_filepicker_highlight
return file_icon, globals.settings.style_text

def display(self):
return f"{self.icon} {self.name}"

def __eq__(self, other):
return isinstance(other, self.__class__) and self.name == other.name

class FilePicker:
flags = (
Expand All @@ -34,13 +71,13 @@ class FilePicker:
def __init__(
self,
title="File picker",
dir_picker=False,
picker_type: PickerType | None = None,
start_dir: str | pathlib.Path = None,
callback: typing.Callable = None,
buttons: list[str] = [],
custom_popup_flags=0
custom_popup_flags=0,
):
self.current = 0
self.current = -1
self.title = title
self.active = True
self.elapsed = 0.0
Expand All @@ -49,11 +86,13 @@ def __init__(
self.selected: str = None
self.filter_box_text = ""
self.update_filter = False
self.items: list[str] = []
self.dir_picker = dir_picker
self.items: list[ListItem] = []
self.dir: pathlib.Path = None
self.error: str | None = None
self.picker_type = picker_type
self.flags = custom_popup_flags or self.flags
self.windows = sys.platform.startswith("win")
self.dir_picker = picker_type == PickerType.Dirs
if self.windows:
self.drives: list[str] = []
self.current_drive = 0
Expand All @@ -76,19 +115,20 @@ def refresh(self):
if self.current != -1:
selected = self.items[self.current]
else:
selected = ""
selected = None
self.error = None
self.items.clear()
try:
items = list(filter(lambda item: self.filter_box_text.lower() in item.name.lower(), self.dir.iterdir()))
if len(items) > 0:
items.sort(key=lambda item: item.name.lower()) # Sort alphabetically
items.sort(key=lambda item: item.is_dir(), reverse=True) # Sort dirs first
for item in items:
self.items.append((dir_icon if item.is_dir() else file_icon) + item.name)
paths = list(filter(lambda path: self.filter_box_text.lower() in path.name.lower(), self.dir.iterdir()))
if len(paths) > 0:
paths.sort(key=lambda path: path.name.lower()) # Sort alphabetically
paths.sort(key=lambda path: path.is_dir(), reverse=True) # Sort dirs first
for path in paths:
self.items.append(ListItem(path, self.picker_type))
else:
self.items.append("No items match your filter!" if self.filter_box_text else "This folder is empty!")
self.error = "No items match your filter!" if self.filter_box_text else "This folder is empty!"
except Exception:
self.items.append("Cannot open this folder!")
self.error = "Cannot open this folder!"
if self.windows:
self.drives.clear()
i = -1
Expand Down Expand Up @@ -161,20 +201,36 @@ def tick(self, popup_uuid: str = ""):
width = imgui.get_item_rect_size().x

# Main list
imgui.set_next_item_width(width)
imgui.push_style_color(imgui.COLOR_HEADER, *style.colors[imgui.COLOR_BUTTON_HOVERED]) # added
_, value = imgui.listbox(f"###file_list", self.current, self.items, (size.y * 0.65) / imgui.get_frame_height())
imgui.pop_style_color() # added
if value != -1:
self.current = min(max(value, 0), len(self.items) - 1)
height = size.y * 0.65
if self.error:
with imgui.begin_child("###file_list_error", height=height, border=True):
text_size = imgui.calc_text_size(self.error)
imgui.set_cursor_pos_x((width - text_size.x) / 2)
imgui.set_cursor_pos_y(imgui.get_cursor_pos_y() + (height / 2) - text_size.y)
imgui.text(self.error)
else:
imgui.set_next_item_width(width)
header_color = (*style.colors[imgui.COLOR_BUTTON_HOVERED][:3], 0.3)
imgui.push_style_color(imgui.COLOR_HEADER, *header_color) # added
imgui.push_style_color(imgui.COLOR_HEADER_HOVERED, *header_color) # added
imgui.push_style_color(imgui.COLOR_HEADER_ACTIVE, *header_color) # added
with imgui.begin_list_box(f"###file_list", height=height) as listbox:
if listbox.opened:
for i, item in enumerate(self.items):
imgui.push_style_color(imgui.COLOR_TEXT, *item.color)
if imgui.selectable(item.display(), self.current == i)[0]:
self.current = i
imgui.pop_style_color()
imgui.pop_style_color(3) # added
if self.current != -1:
self.current = min(max(self.current, 0), len(self.items) - 1)
item = self.items[self.current]
is_dir = item.startswith(dir_icon)
is_file = item.startswith(file_icon)
is_dir, is_file = item.is_dir, item.is_file
if imgui.is_item_hovered() and imgui.is_mouse_double_clicked():
if is_dir:
self.goto(self.dir / item[len(dir_icon):])
self.goto(item.path)
elif is_file and not self.dir_picker:
self.selected = str(self.dir / item[len(file_icon):])
self.selected = str(item.path)
imgui.close_current_popup()
closed = True # added
else:
Expand All @@ -198,10 +254,10 @@ def tick(self, popup_uuid: str = ""):
imgui.internal.push_item_flag(imgui.internal.ITEM_DISABLED, True)
imgui.push_style_var(imgui.STYLE_ALPHA, style.alpha * 0.5)
if imgui.button(ok_icon):
if value == -1:
if self.current == -1:
self.selected = str(self.dir)
else:
self.selected = str(self.dir / item[len(dir_icon if self.dir_picker else file_icon):])
self.selected = str(item.path)
imgui.close_current_popup()
closed = True # added
if not (is_file and not self.dir_picker) and not (is_dir and self.dir_picker):
Expand All @@ -211,10 +267,10 @@ def tick(self, popup_uuid: str = ""):
imgui.same_line()
prev_pos_x = imgui.get_cursor_pos_x()
if (is_file and not self.dir_picker) or (is_dir and self.dir_picker):
if value == -1:
if self.current == -1:
imgui.text(f"Selected: {self.dir.name}")
else:
imgui.text(f"Selected: {item[len(dir_icon if self.dir_picker else file_icon):]}")
imgui.text(f"Selected: {item.name}")
# Filter bar
if imgui.is_topmost() and not imgui.is_any_item_active() and (globals.gui.input_chars or any(io.keys_down)): # added
if imgui.is_key_pressed(glfw.KEY_BACKSPACE): # added
Expand Down Expand Up @@ -257,7 +313,7 @@ def __init__(
):
super().__init__(
title=title,
dir_picker=True,
picker_type=PickerType.Dirs,
start_dir=start_dir,
callback=callback,
buttons=buttons,
Expand Down
20 changes: 14 additions & 6 deletions modules/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -1913,6 +1913,7 @@ def select_callback(selected):
game.set_image_sync(pathlib.Path(selected).read_bytes())
utils.push_popup(filepicker.FilePicker(
title=f"Select or drop image for {game.name}",
picker_type=filepicker.PickerType.Media,
callback=select_callback
).tick)
if imgui.selectable(f"{icons.trash_can_outline} Reset image", False)[0]:
Expand Down Expand Up @@ -3891,6 +3892,7 @@ def callback(selected: str):
async_thread.run(db.update_settings("browser_custom_executable"))
utils.push_popup(filepicker.FilePicker(
title="Select or drop browser executable",
picker_type=filepicker.PickerType.Execs,
start_dir=set.browser_custom_executable,
callback=callback
).tick)
Expand Down Expand Up @@ -4278,6 +4280,7 @@ def callback(selected):
buttons={
f"{icons.check} Ok": lambda: utils.push_popup(filepicker.FilePicker(
title="Select or drop bookmark file",
picker_type=filepicker.PickerType.Bookmarks,
callback=callback
).tick),
f"{icons.cancel} Cancel": None
Expand Down Expand Up @@ -4574,15 +4577,19 @@ def select_callback(selected):
draw_settings_label("Text dim:")
draw_settings_color("style_text_dim")

draw_settings_label("Filepicker highlight:")
draw_settings_color("style_filepicker_highlight")

draw_settings_label("Defaults:")
if imgui.button("Restore", width=right_width):
set.style_corner_radius = DefaultStyle.corner_radius
set.style_accent = colors.hex_to_rgba_0_1(DefaultStyle.accent)
set.style_alt_bg = colors.hex_to_rgba_0_1(DefaultStyle.alt_bg)
set.style_bg = colors.hex_to_rgba_0_1(DefaultStyle.bg)
set.style_border = colors.hex_to_rgba_0_1(DefaultStyle.border)
set.style_text = colors.hex_to_rgba_0_1(DefaultStyle.text)
set.style_text_dim = colors.hex_to_rgba_0_1(DefaultStyle.text_dim)
set.style_accent = colors.hex_to_rgba_0_1(DefaultStyle.accent)
set.style_alt_bg = colors.hex_to_rgba_0_1(DefaultStyle.alt_bg)
set.style_bg = colors.hex_to_rgba_0_1(DefaultStyle.bg)
set.style_border = colors.hex_to_rgba_0_1(DefaultStyle.border)
set.style_text = colors.hex_to_rgba_0_1(DefaultStyle.text)
set.style_text_dim = colors.hex_to_rgba_0_1(DefaultStyle.text_dim)
set.style_filepicker_highlight = colors.hex_to_rgba_0_1(DefaultStyle.filepicker_highlight)
self.refresh_styles()
async_thread.run(db.update_settings(
"style_corner_radius",
Expand All @@ -4592,6 +4599,7 @@ def select_callback(selected):
"style_border",
"style_text",
"style_text_dim",
"style_filepicker_highlight",
))

imgui.end_table()
Expand Down
16 changes: 9 additions & 7 deletions modules/structs.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,13 +171,14 @@ def format(self):


class DefaultStyle:
accent = "#d4202e"
alt_bg = "#101010"
bg = "#0a0a0a"
border = "#454545"
corner_radius = 6
text = "#ffffff"
text_dim = "#808080"
accent = "#d4202e"
alt_bg = "#101010"
bg = "#0a0a0a"
border = "#454545"
corner_radius = 6
text = "#ffffff"
text_dim = "#808080"
filepicker_highlight = "#80FF00"


@dataclasses.dataclass
Expand Down Expand Up @@ -675,6 +676,7 @@ class Settings:
style_corner_radius : int
style_text : tuple[float]
style_text_dim : tuple[float]
style_filepicker_highlight : tuple[float]
tags_highlights : dict[Tag, TagHighlight]
timestamp_format : str
use_parser_processes : bool
Expand Down