You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

368 lines
16 KiB

from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QListWidget, QLineEdit,
QLabel, QCheckBox, QPushButton, QFormLayout, QListWidgetItem, QSplitter, QTreeWidget,
QTreeWidgetItem, QDialog, QDialogButtonBox, QComboBox, QMessageBox, QSpinBox, QMenu, QTabWidget,
QTextEdit)
from PyQt6.QtCore import Qt, QSize, QTimer, QMetaObject
from PyQt6.QtGui import QPixmap, QFontMetrics, QColor, QAction
from .main_window_controller import MainWindowController
from utility.functions import get_display_name
from db import db
import json
class PokemonUI(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.controller = MainWindowController(self)
self.setup_ui()
data = db.get_list_of_pokemon_forms()
self.controller.initialize_pokemon_list(data)
def setup_ui(self):
main_layout = QVBoxLayout(self)
self.tab_widget = QTabWidget()
main_layout.addWidget(self.tab_widget)
self.setup_main_tab()
self.setup_db_operations_tab()
self.setup_manage_encounters_tab()
self.setup_plan_tab()
self.save_button = QPushButton("Save Changes")
self.save_button.clicked.connect(self.controller.save_changes)
main_layout.addWidget(self.save_button)
self.export_button = QPushButton("Export Database")
self.export_button.clicked.connect(self.controller.export_database)
main_layout.addWidget(self.export_button)
def setup_main_tab(self):
main_tab = QWidget()
main_tab_layout = QHBoxLayout(main_tab)
self.tab_widget.addTab(main_tab, "Main")
self.create_main_left_panel(main_tab_layout)
self.create_main_right_panel(main_tab_layout)
def create_main_left_panel(self, main_tab_layout):
left_layout = QVBoxLayout()
search_layout = QHBoxLayout()
self.search_bar = QLineEdit()
self.search_bar.setPlaceholderText("Search Pokémon...")
self.search_bar.textChanged.connect(self.controller.filter_pokemon_list)
search_layout.addWidget(self.search_bar)
left_layout.addLayout(search_layout)
self.pokemon_list = QListWidget()
self.pokemon_list.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
self.pokemon_list.customContextMenuRequested.connect(self.controller.show_pokemon_context_menu)
self.pokemon_list.currentItemChanged.connect(self.controller.on_pokemon_selected)
left_layout.addWidget(self.pokemon_list)
self.highlight_no_encounters = QCheckBox("Highlight Pokémon without encounters")
self.highlight_no_encounters.stateChanged.connect(self.controller.filter_pokemon_list)
left_layout.addWidget(self.highlight_no_encounters)
self.filter_home_storable = QCheckBox("Show only Home-storable Pokémon")
self.filter_home_storable.stateChanged.connect(self.controller.filter_pokemon_list)
left_layout.addWidget(self.filter_home_storable)
main_tab_layout.addLayout(left_layout, 1)
def create_main_right_panel(self, main_tab_layout):
right_layout = QVBoxLayout()
# Left side of right panel: Text information
info_layout = QHBoxLayout()
text_layout = QVBoxLayout()
self.edit_form = QFormLayout()
self.name_label = QLabel()
self.form_name_label = QLabel()
self.national_dex_label = QLabel()
self.generation_label = QLabel()
self.home_checkbox = QCheckBox("Available in Home")
self.is_baby_form_checkbox = QCheckBox("Is Baby Form")
self.edit_form.addRow("Name:", self.name_label)
self.edit_form.addRow("Form:", self.form_name_label)
self.edit_form.addRow("National Dex:", self.national_dex_label)
self.edit_form.addRow("Generation:", self.generation_label)
self.edit_form.addRow(self.home_checkbox)
self.edit_form.addRow(self.is_baby_form_checkbox)
text_layout.addLayout(self.edit_form)
# Right side of right panel: Image
image_layout = QVBoxLayout()
self.image_label = QLabel()
self.image_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.image_label.setFixedSize(150, 150)
image_layout.addWidget(self.image_label)
image_layout.addStretch(1)
info_layout.addLayout(text_layout)
info_layout.addLayout(image_layout)
second_half_layout = QVBoxLayout()
# Evolution chain tree
self.evolution_tree = QTreeWidget()
self.evolution_tree.setHeaderLabels(["Pokémon", "Evolution Method"])
self.evolution_tree.setColumnWidth(0, 200)
second_half_layout.addWidget(self.evolution_tree)
# Add Locations tree
self.locations_tree = QTreeWidget()
self.locations_tree.setHeaderLabels(["Game/Location", "Details"])
self.locations_tree.setColumnWidth(0, 200)
self.locations_tree.itemDoubleClicked.connect(self.controller.edit_encounter)
second_half_layout.addWidget(QLabel("Locations:"))
second_half_layout.addWidget(self.locations_tree)
# Add New Encounter button
self.add_encounter_button = QPushButton("Add New Encounter")
self.add_encounter_button.clicked.connect(self.controller.add_new_encounter)
second_half_layout.addWidget(self.add_encounter_button)
# Move buttons to the bottom
second_half_layout.addStretch(1)
# Add New Evolution button
self.add_evolution_button = QPushButton("Add New Evolution")
self.add_evolution_button.clicked.connect(self.controller.add_new_evolution)
second_half_layout.addWidget(self.add_evolution_button)
right_layout.addLayout(info_layout)
right_layout.addLayout(second_half_layout)
main_tab_layout.addLayout(right_layout, 1)
def setup_db_operations_tab(self):
db_tab = QWidget()
db_tab_layout = QVBoxLayout(db_tab)
self.tab_widget.addTab(db_tab, "Database Operations")
gather_forms_btn = QPushButton("Gather Pokémon Forms")
gather_forms_btn.clicked.connect(self.controller.gather_pokemon_forms)
db_tab_layout.addWidget(gather_forms_btn)
gather_home_btn = QPushButton("Gather Home Storage Info")
gather_home_btn.clicked.connect(self.controller.gather_home_storage_info)
db_tab_layout.addWidget(gather_home_btn)
gather_evolutions_btn = QPushButton("Gather Evolution Information")
gather_evolutions_btn.clicked.connect(self.controller.gather_evolution_info)
db_tab_layout.addWidget(gather_evolutions_btn)
gather_evolutions_btn = QPushButton("Gather Baby Status")
gather_evolutions_btn.clicked.connect(self.controller.gather_baby_status)
db_tab_layout.addWidget(gather_evolutions_btn)
gather_encounters_btn = QPushButton("Gather Encounter Information")
gather_encounters_btn.clicked.connect(self.controller.gather_encounter_info)
db_tab_layout.addWidget(gather_encounters_btn)
gather_marks_btn = QPushButton("Gather Marks Information")
gather_marks_btn.clicked.connect(self.controller.gather_marks_info)
db_tab_layout.addWidget(gather_marks_btn)
load_shiftable_forms_btn = QPushButton("Load Shiftable Forms")
load_shiftable_forms_btn.clicked.connect(self.controller.load_shiftable_forms)
db_tab_layout.addWidget(load_shiftable_forms_btn)
self.progress_text = QTextEdit()
self.progress_text.setReadOnly(True)
self.progress_text.setMinimumHeight(200) # Set a minimum height
db_tab_layout.addWidget(self.progress_text)
db_tab_layout.addStretch(1)
reinit_db_btn = QPushButton("Clear and Reinitialize Database")
reinit_db_btn.clicked.connect(self.controller.reinitialize_database)
db_tab_layout.addWidget(reinit_db_btn)
def setup_manage_encounters_tab(self):
manage_encounters = QWidget()
self.manage_encounters_tab = QHBoxLayout(manage_encounters)
self.tab_widget.addTab(manage_encounters, "Manage Encounters")
left_layout = QVBoxLayout()
self.exclusive_set_list = QListWidget()
self.exclusive_set_list.currentItemChanged.connect(self.controller.on_exclusive_set_selected)
left_layout.addWidget(QLabel("Exclusive Encounter Sets:"))
left_layout.addWidget(self.exclusive_set_list)
add_set_button = QPushButton("Add New Set")
add_set_button.clicked.connect(self.controller.add_new_exclusive_set)
left_layout.addWidget(add_set_button)
# Right side: Set details and encounters
right_layout = QVBoxLayout()
self.set_name_label = QLabel()
self.set_description_label = QLabel()
self.set_game_label = QLabel()
right_layout.addWidget(self.set_name_label)
right_layout.addWidget(self.set_description_label)
right_layout.addWidget(self.set_game_label)
self.encounter_list = QListWidget()
self.encounter_list.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
self.encounter_list.customContextMenuRequested.connect(self.controller.show_encounter_context_menu)
right_layout.addWidget(QLabel("Encounters in Set:"))
right_layout.addWidget(self.encounter_list)
add_encounter_button = QPushButton("Add Encounter to Set")
add_encounter_button.clicked.connect(self.controller.add_encounter_to_set)
right_layout.addWidget(add_encounter_button)
self.manage_encounters_tab.addLayout(left_layout, 1)
self.manage_encounters_tab.addLayout(right_layout, 2)
def setup_plan_tab(self):
plan_tab = QWidget()
plan_tab_layout = QVBoxLayout(plan_tab)
self.tab_widget.addTab(plan_tab, "Plan Generation")
plan_tab_layout.addStretch(1)
generate_plan__btn = QPushButton("Generate Plan")
generate_plan__btn.clicked.connect(self.controller.generate_plan)
plan_tab_layout.addWidget(generate_plan__btn)
def update_pokemon_forms(self, data):
self.pokemon_list.clear()
for pokemon in data:
display_name = get_display_name(pokemon, not pokemon["gender_relevant"])
item = QListWidgetItem(display_name)
item.setData(Qt.ItemDataRole.UserRole, pokemon["pfic"])
self.pokemon_list.addItem(item)
def update_evolution_tree(self, evolution_chains, selected_pfic):
self.evolution_tree.clear()
tree_items = {}
for chains in evolution_chains["predecessors"]:
for pfic, method in chains:
pokemon_details = db.get_pokemon_details(pfic)
display_name = get_display_name(pokemon_details, not pokemon_details["gender_relevant"])
item = QTreeWidgetItem([display_name, method if method else ""])
item.setData(0, Qt.ItemDataRole.UserRole, pfic)
tree_items[pfic] = item
if pfic == selected_pfic:
item.setBackground(0, QColor(255, 255, 0, 100)) # Highlight selected Pokémon
# Second pass: build the tree structure
root = None
for pfic, method in chains:
item = tree_items[pfic]
# Find the parent of this item
parent_pfic, method = db.get_previous_evolution(pfic)
if parent_pfic:
parent_item = tree_items.get(parent_pfic)
if parent_item:
parent_item.addChild(item)
elif not root:
root = item
self.evolution_tree.addTopLevelItem(root)
for chains in evolution_chains["successors"]:
for pfic, method in chains:
pokemon_details = db.get_pokemon_details(pfic)
display_name = get_display_name(pokemon_details, not pokemon_details["gender_relevant"])
item = QTreeWidgetItem([display_name, method if method else ""])
item.setData(0, Qt.ItemDataRole.UserRole, pfic)
tree_items[pfic] = item
if pfic == selected_pfic:
item.setBackground(0, QColor(255, 255, 0, 100)) # Highlight selected Pokémon
# Second pass: build the tree structure
root = None
for pfic, method in chains:
item = tree_items[pfic]
# Find the parent of this item
parent_pfic, method = db.get_previous_evolution(pfic)
if parent_pfic:
parent_item = tree_items.get(parent_pfic)
if parent_item:
parent_item.addChild(item)
elif not root:
root = item
self.evolution_tree.addTopLevelItem(root)
# Expand the entire tree
self.evolution_tree.expandAll()
# Scroll to and select the current Pokémon
if selected_pfic in tree_items:
current_item = tree_items[selected_pfic]
self.evolution_tree.scrollToItem(current_item)
self.evolution_tree.setCurrentItem(current_item)
def update_encounter_list(self, encounters, pfic):
self.locations_tree.clear()
game_items = {}
for encounter in encounters:
pfic = encounter["PFIC"]
game_id = encounter["game_id"]
type = encounter["type"]
if type == "event":
continue
if type == "evolve":
continue
data = json.loads(encounter["data"])
game = db.get_game_by_id(game_id)
game_name = game["name"]
location = data["location"]
if game_name not in game_items:
#print(f'finding generation for {game}')
game_item = QTreeWidgetItem([game_name])
game_items[game_name] = game_item
# Use generation for sorting, default to 0 if not found
game_item.setData(0, Qt.ItemDataRole.UserRole, game["generation"])
#print(f'generation for {game} is {generation}')
location_item = QTreeWidgetItem([location])
details = []
if "day" in data:
details.append(f"Day: {data["day"]}")
if "time" in data:
details.append(f"Time: {data["time"]}")
if "dual_slot" in data:
details.append(f"Dual Slot: {data["dual_slot"]}")
if "static_encounter" in data:
details.append(f"Static Encounter (Count: {data["static_encounter_count"]})")
if "extra_text" in data:
details.append(f"Extra: {data["extra_text"]}")
if "stars" in data:
details.append(f"Stars: {data["stars"]}")
if "fishing" in data:
details.append(f"Fishing")
if "rods" in data:
details.append(f"Rods: {data["rods"]}")
location_item.setText(1, ", ".join(details))
game_items[game_name].addChild(location_item)
# Sort game items by generation and add them to the tree
sorted_game_items = sorted(game_items.values(), key=lambda x: x.data(0, Qt.ItemDataRole.UserRole))
self.locations_tree.addTopLevelItems(sorted_game_items)
self.locations_tree.expandAll()
# Update the cache for this Pokémon
#self.encounter_cache[pfic] = len(encounters) > 0
# After updating the locations tree
#self.update_pokemon_list_highlights()