feat: Introduce db_queries for card data, migrations, and updates, and effects_view and theme for GUI components.
This commit is contained in:
@@ -522,6 +522,49 @@ def get_unique_effect_names(card_id):
|
|||||||
conn.close()
|
conn.close()
|
||||||
return rows
|
return rows
|
||||||
|
|
||||||
|
def search_owned_effects(search_term):
|
||||||
|
"""
|
||||||
|
Search for effects among owned cards.
|
||||||
|
Returns list of (card_id, card_name, image_path, effect_name, effect_value, level)
|
||||||
|
"""
|
||||||
|
conn = get_conn()
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
# We need to join support_effects with owned_cards to get the level
|
||||||
|
# But wait, owned_cards has a level column. support_effects stores effects for specific levels.
|
||||||
|
# So we need to match support_effects.level with owned_cards.level
|
||||||
|
# OR find the effect for the closest level <= owned level (if effects aren't stored for every single level)
|
||||||
|
# The current DB schema seems to store effects for specific levels (1, 5, 10, ...).
|
||||||
|
# If a card is level 49, `get_effects_at_level` usually queries for exact level match.
|
||||||
|
# Let's check `get_effects_at_level` implementation: "WHERE card_id = ? AND level = ?"
|
||||||
|
# So if I have a card at level 49, and effects are only defined at 45 and 50, query for 49 returns nothing?
|
||||||
|
# That would be a bug or assumption in the current app.
|
||||||
|
# Let's look at `update_progression_table` in `effects_view.py`. It does some "nearest level" logic.
|
||||||
|
# For this search feature, to be robust, we should probably fetch ALL effects for the card
|
||||||
|
# and filter for the one active at the owned level.
|
||||||
|
# OR, assuming the scraper/DB populates "current" effects effectively.
|
||||||
|
# Actually, the most robust way in SQL for "value at level X" given sparse data is complex.
|
||||||
|
# However, let's assume for now we want exact matches or we'll handle the "effective level" logic in Python?
|
||||||
|
# No, that's too slow for search.
|
||||||
|
# Let's look at how `get_effects_at_level` is used.
|
||||||
|
# It is used in `update_current_effects` with `self.level_var.get()`.
|
||||||
|
# It expects an exact match.
|
||||||
|
# So we should probably join on `oc.level`.
|
||||||
|
|
||||||
|
query = """
|
||||||
|
SELECT sc.card_id, sc.name, sc.image_path, se.effect_name, se.effect_value, oc.level
|
||||||
|
FROM owned_cards oc
|
||||||
|
JOIN support_cards sc ON oc.card_id = sc.card_id
|
||||||
|
JOIN support_effects se ON oc.card_id = se.card_id AND oc.level = se.level
|
||||||
|
WHERE se.effect_name LIKE ?
|
||||||
|
ORDER BY sc.name
|
||||||
|
"""
|
||||||
|
|
||||||
|
cur.execute(query, (f"%{search_term}%",))
|
||||||
|
rows = cur.fetchall()
|
||||||
|
conn.close()
|
||||||
|
return rows
|
||||||
|
|
||||||
# ============================================
|
# ============================================
|
||||||
# Hint Queries
|
# Hint Queries
|
||||||
# ============================================
|
# ============================================
|
||||||
|
|||||||
@@ -1,298 +1,139 @@
|
|||||||
"""
|
"""
|
||||||
Effects View - Display support effects at all levels with interactive slider
|
Effects Search View - Search for effects across all owned cards
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import ttk, messagebox
|
from tkinter import ttk, messagebox
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
|
||||||
from db.db_queries import get_all_effects, get_effects_at_level, get_unique_effect_names, get_card_by_id
|
from db.db_queries import search_owned_effects
|
||||||
from gui.theme import (
|
from gui.theme import (
|
||||||
BG_DARK, BG_MEDIUM, BG_LIGHT, BG_HIGHLIGHT,
|
BG_DARK, BG_MEDIUM, BG_LIGHT, BG_HIGHLIGHT,
|
||||||
ACCENT_PRIMARY, ACCENT_SECONDARY, ACCENT_SUCCESS, ACCENT_TERTIARY,
|
ACCENT_PRIMARY, ACCENT_SECONDARY, ACCENT_SUCCESS, ACCENT_TERTIARY,
|
||||||
TEXT_PRIMARY, TEXT_SECONDARY, TEXT_MUTED,
|
TEXT_PRIMARY, TEXT_SECONDARY, TEXT_MUTED,
|
||||||
FONT_HEADER, FONT_SUBHEADER, FONT_BODY, FONT_BODY_BOLD, FONT_SMALL, FONT_MONO,
|
FONT_HEADER, FONT_SUBHEADER, FONT_BODY, FONT_BODY_BOLD, FONT_SMALL,
|
||||||
create_styled_button, create_styled_text, create_card_frame,
|
create_styled_button, create_styled_entry
|
||||||
EFFECT_DESCRIPTIONS
|
|
||||||
)
|
)
|
||||||
|
from utils import resolve_image_path
|
||||||
|
|
||||||
class EffectsFrame(ttk.Frame):
|
class EffectsFrame(ttk.Frame):
|
||||||
"""Frame for viewing support effects at different levels"""
|
"""Frame for searching effects across owned cards"""
|
||||||
|
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.current_card_id = None
|
|
||||||
self.current_card_name = None
|
|
||||||
self.max_level = 50
|
|
||||||
|
|
||||||
self.create_widgets()
|
self.create_widgets()
|
||||||
|
|
||||||
def create_widgets(self):
|
def create_widgets(self):
|
||||||
"""Create the effects view interface"""
|
"""Create the effects search interface"""
|
||||||
# Header
|
# Header / Search Bar
|
||||||
header_frame = tk.Frame(self, bg=BG_DARK)
|
header_frame = tk.Frame(self, bg=BG_DARK)
|
||||||
header_frame.pack(fill=tk.X, padx=20, pady=15)
|
header_frame.pack(fill=tk.X, padx=20, pady=15)
|
||||||
|
|
||||||
self.card_label = tk.Label(header_frame, text="📊 Select a card from the Card List tab",
|
# Search container
|
||||||
font=FONT_HEADER, bg=BG_DARK, fg=ACCENT_PRIMARY)
|
search_container = tk.Frame(header_frame, bg=BG_DARK)
|
||||||
self.card_label.pack(side=tk.LEFT)
|
search_container.pack(fill=tk.X)
|
||||||
|
|
||||||
# Legend Button
|
tk.Label(search_container, text="🔍 Search Effect:",
|
||||||
legend_btn = create_styled_button(header_frame, text="❓ Legend",
|
font=FONT_HEADER, bg=BG_DARK, fg=TEXT_PRIMARY).pack(side=tk.LEFT, padx=(0, 10))
|
||||||
command=self.show_legend, style_type='default')
|
|
||||||
legend_btn.config(font=FONT_SMALL, padx=10, pady=4)
|
|
||||||
legend_btn.pack(side=tk.RIGHT)
|
|
||||||
|
|
||||||
# Level control frame
|
self.search_var = tk.StringVar()
|
||||||
control_frame = tk.Frame(self, bg=BG_MEDIUM, padx=15, pady=12)
|
self.search_entry = create_styled_entry(search_container, textvariable=self.search_var)
|
||||||
control_frame.pack(fill=tk.X, padx=20)
|
self.search_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 10))
|
||||||
|
self.search_entry.bind('<Return>', lambda e: self.perform_search())
|
||||||
|
|
||||||
# Level label
|
search_btn = create_styled_button(search_container, text="Search",
|
||||||
tk.Label(control_frame, text="Level:", font=FONT_BODY,
|
command=self.perform_search, style_type='primary')
|
||||||
bg=BG_MEDIUM, fg=TEXT_SECONDARY).pack(side=tk.LEFT)
|
search_btn.pack(side=tk.LEFT)
|
||||||
|
|
||||||
# Level display with increment/decrement buttons
|
# Example/Help text
|
||||||
level_ctrl = tk.Frame(control_frame, bg=BG_MEDIUM)
|
help_frame = tk.Frame(header_frame, bg=BG_DARK)
|
||||||
level_ctrl.pack(side=tk.LEFT, padx=15)
|
help_frame.pack(fill=tk.X, pady=(5, 0))
|
||||||
|
tk.Label(help_frame, text="Examples: Friendship, Motivation, Race Bonus, Skill Pt",
|
||||||
|
font=FONT_SMALL, bg=BG_DARK, fg=TEXT_MUTED).pack(side=tk.LEFT)
|
||||||
|
|
||||||
# Decrement button
|
# Results Area
|
||||||
dec_btn = tk.Button(level_ctrl, text="−", font=FONT_HEADER,
|
results_frame = ttk.LabelFrame(self, text=" Search Results (Owned Cards) ", padding=10)
|
||||||
bg=BG_LIGHT, fg=TEXT_PRIMARY, bd=0, width=2,
|
results_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=(0, 20))
|
||||||
activebackground=BG_HIGHLIGHT, cursor='hand2',
|
|
||||||
command=self.decrement_level)
|
|
||||||
dec_btn.pack(side=tk.LEFT)
|
|
||||||
|
|
||||||
self.level_var = tk.IntVar(value=50)
|
# Treeview
|
||||||
self.level_display = tk.Label(level_ctrl, text="50", width=4, font=FONT_HEADER,
|
columns = ('card', 'level', 'current_value', 'effect_name')
|
||||||
bg=BG_LIGHT, fg=ACCENT_PRIMARY, padx=10)
|
self.tree = ttk.Treeview(results_frame, columns=columns, show='headings', selectmode='browse')
|
||||||
self.level_display.pack(side=tk.LEFT, padx=2)
|
|
||||||
|
|
||||||
# Increment button
|
self.tree.heading('card', text='Card Name', anchor='w')
|
||||||
inc_btn = tk.Button(level_ctrl, text="+", font=FONT_HEADER,
|
self.tree.heading('level', text='Level', anchor='center')
|
||||||
bg=BG_LIGHT, fg=TEXT_PRIMARY, bd=0, width=2,
|
self.tree.heading('current_value', text='Value', anchor='center')
|
||||||
activebackground=BG_HIGHLIGHT, cursor='hand2',
|
self.tree.heading('effect_name', text='Effect Name', anchor='w')
|
||||||
command=self.increment_level)
|
|
||||||
inc_btn.pack(side=tk.LEFT)
|
|
||||||
|
|
||||||
# Quick level buttons
|
self.tree.column('card', width=250)
|
||||||
button_frame = tk.Frame(control_frame, bg=BG_MEDIUM)
|
self.tree.column('level', width=60, anchor='center')
|
||||||
button_frame.pack(side=tk.LEFT, padx=25)
|
self.tree.column('current_value', width=80, anchor='center')
|
||||||
|
self.tree.column('effect_name', width=150)
|
||||||
|
|
||||||
quick_levels = [25, 30, 35, 40, 45, 50]
|
scrollbar = ttk.Scrollbar(results_frame, orient=tk.VERTICAL, command=self.tree.yview)
|
||||||
for lvl in quick_levels:
|
self.tree.configure(yscrollcommand=scrollbar.set)
|
||||||
btn = create_styled_button(button_frame, text=f"Lv{lvl}",
|
|
||||||
command=lambda l=lvl: self.set_level(l),
|
|
||||||
style_type='default')
|
|
||||||
btn.config(width=5, font=FONT_SMALL, padx=6, pady=3)
|
|
||||||
btn.pack(side=tk.LEFT, padx=3)
|
|
||||||
|
|
||||||
# Main content area
|
self.tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
||||||
content_frame = tk.Frame(self, bg=BG_DARK)
|
|
||||||
content_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=15)
|
|
||||||
|
|
||||||
# Left: Current level effects
|
|
||||||
left_frame = ttk.LabelFrame(content_frame, text=" Current Level Effects ", padding=12)
|
|
||||||
left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 10))
|
|
||||||
|
|
||||||
self.current_effects = create_styled_text(left_frame, height=15)
|
|
||||||
self.current_effects.pack(fill=tk.BOTH, expand=True)
|
|
||||||
self.current_effects.config(state=tk.DISABLED)
|
|
||||||
|
|
||||||
# Right: Effect progression table
|
|
||||||
right_frame = ttk.LabelFrame(content_frame, text=" Effect Progression ", padding=12)
|
|
||||||
right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
|
|
||||||
|
|
||||||
# Treeview for effect table
|
|
||||||
columns = ('effect', 'lv1', 'lv25', 'lv40', 'lv50')
|
|
||||||
self.effects_tree = ttk.Treeview(right_frame, columns=columns, show='headings', height=12)
|
|
||||||
|
|
||||||
self.effects_tree.heading('effect', text='Effect', anchor='w')
|
|
||||||
self.effects_tree.column('effect', width=140, minwidth=120)
|
|
||||||
|
|
||||||
for col in columns[1:]:
|
|
||||||
level = col.replace('lv', 'Lv ')
|
|
||||||
self.effects_tree.heading(col, text=level)
|
|
||||||
self.effects_tree.column(col, width=65, anchor='center')
|
|
||||||
|
|
||||||
scrollbar = ttk.Scrollbar(right_frame, orient=tk.VERTICAL, command=self.effects_tree.yview)
|
|
||||||
self.effects_tree.configure(yscrollcommand=scrollbar.set)
|
|
||||||
|
|
||||||
self.effects_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
|
||||||
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
||||||
|
|
||||||
def show_legend(self):
|
# Status Label
|
||||||
"""Show effect explanations"""
|
self.status_label = tk.Label(results_frame, text="", bg=BG_MEDIUM, fg=TEXT_SECONDARY, font=FONT_SMALL)
|
||||||
legend = {
|
self.status_label.pack(side=tk.BOTTOM, fill=tk.X, pady=(5, 0))
|
||||||
"Friendship Bonus": "Increases stats gained when training with this support card during Friendship Training (orange aura).",
|
|
||||||
"Motivation Bonus": "Increases stats gained based on your Uma's motivation level.",
|
|
||||||
"Specialty Rate": "Increases the chance of this card appearing in its specialty training.",
|
|
||||||
"Training Bonus": "Flat percentage increase to stats gained in training where this card is present.",
|
|
||||||
"Initial Bond": "Starting gauge value for this card.",
|
|
||||||
"Race Bonus": "Increases stats gained from racing.",
|
|
||||||
"Fan Count Bonus": "Increases fans gained from racing.",
|
|
||||||
"Skill Pt Bonus": "Bonus skill points gained when training with this card.",
|
|
||||||
"Hint Lv": "Starting level of skills taught by this card's hints.",
|
|
||||||
"Hint Rate": "Increases chance of getting a hint event."
|
|
||||||
}
|
|
||||||
|
|
||||||
text = "📖 Effect Explanations:\n\n"
|
def parse_value(self, value_str):
|
||||||
for name, desc in legend.items():
|
"""Parse effect value string to float for sorting"""
|
||||||
text += f"• {name}:\n {desc}\n\n"
|
try:
|
||||||
|
# Extract number from string (e.g. "20%" -> 20, "+15" -> 15)
|
||||||
|
# Remove non-numeric characters except . and -
|
||||||
|
clean = re.sub(r'[^\d.-]', '', str(value_str))
|
||||||
|
return float(clean)
|
||||||
|
except:
|
||||||
|
return -999999.0 # Sort to bottom if invalid
|
||||||
|
|
||||||
messagebox.showinfo("Effect Legend", text)
|
def perform_search(self):
|
||||||
|
"""Execute search and update results"""
|
||||||
|
term = self.search_var.get().strip()
|
||||||
|
if not term:
|
||||||
|
messagebox.showwarning("Search", "Please enter a search term")
|
||||||
|
return
|
||||||
|
|
||||||
|
# clear current
|
||||||
|
for item in self.tree.get_children():
|
||||||
|
self.tree.delete(item)
|
||||||
|
|
||||||
|
# Query DB
|
||||||
|
results = search_owned_effects(term)
|
||||||
|
|
||||||
|
if not results:
|
||||||
|
self.status_label.config(text="No matching effects found among owned cards.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Process and Sort
|
||||||
|
# Row: (card_id, card_name, image_path, effect_name, effect_value, level)
|
||||||
|
processed_results = []
|
||||||
|
for r in results:
|
||||||
|
val_num = self.parse_value(r[4])
|
||||||
|
processed_results.append({
|
||||||
|
'data': r,
|
||||||
|
'sort_val': val_num
|
||||||
|
})
|
||||||
|
|
||||||
|
# Sort by value descending
|
||||||
|
processed_results.sort(key=lambda x: x['sort_val'], reverse=True)
|
||||||
|
|
||||||
|
# Populate Tree
|
||||||
|
for item in processed_results:
|
||||||
|
r = item['data']
|
||||||
|
#Columns: card, level, current_value, effect_name
|
||||||
|
values = (r[1], f"Lv {r[5]}", r[4], r[3])
|
||||||
|
self.tree.insert('', tk.END, values=values)
|
||||||
|
|
||||||
|
self.status_label.config(text=f"Found {len(processed_results)} owned cards with matching effects.")
|
||||||
|
|
||||||
|
# Compatibility methods for main_window integration (empty as we don't need them anymore)
|
||||||
def set_card(self, card_id):
|
def set_card(self, card_id):
|
||||||
"""Load a card's effects"""
|
pass
|
||||||
self.current_card_id = card_id
|
|
||||||
|
|
||||||
# Get card info for max level
|
|
||||||
card = get_card_by_id(card_id)
|
|
||||||
if card:
|
|
||||||
self.current_card_name = card[1]
|
|
||||||
self.max_level = card[4]
|
|
||||||
if self.level_var.get() > self.max_level:
|
|
||||||
self.level_var.set(self.max_level)
|
|
||||||
self.level_display.config(text=str(self.max_level))
|
|
||||||
|
|
||||||
self.card_label.config(text=f"📊 {self.current_card_name}")
|
|
||||||
|
|
||||||
# Update displays
|
|
||||||
self.update_current_effects()
|
|
||||||
self.update_progression_table()
|
|
||||||
|
|
||||||
def set_level(self, level):
|
|
||||||
"""Set level from quick button"""
|
|
||||||
if level <= self.max_level:
|
|
||||||
self.level_var.set(level)
|
|
||||||
self.level_display.config(text=str(level))
|
|
||||||
self.update_current_effects()
|
|
||||||
|
|
||||||
def increment_level(self):
|
|
||||||
"""Increase level by 1"""
|
|
||||||
current = self.level_var.get()
|
|
||||||
if current < self.max_level:
|
|
||||||
self.set_level(current + 1)
|
|
||||||
|
|
||||||
def decrement_level(self):
|
|
||||||
"""Decrease level by 1"""
|
|
||||||
current = self.level_var.get()
|
|
||||||
if current > 1:
|
|
||||||
self.set_level(current - 1)
|
|
||||||
|
|
||||||
def update_current_effects(self):
|
|
||||||
"""Update the current level effects display"""
|
|
||||||
self.current_effects.config(state=tk.NORMAL)
|
|
||||||
self.current_effects.delete('1.0', tk.END)
|
|
||||||
|
|
||||||
# Configure tags
|
|
||||||
self.current_effects.tag_configure('header', font=FONT_SUBHEADER, foreground=ACCENT_PRIMARY)
|
|
||||||
self.current_effects.tag_configure('highlight', foreground=ACCENT_SUCCESS)
|
|
||||||
self.current_effects.tag_configure('effect_name', foreground=TEXT_SECONDARY)
|
|
||||||
self.current_effects.tag_configure('effect_value', foreground=TEXT_PRIMARY, font=FONT_BODY_BOLD)
|
|
||||||
self.current_effects.tag_configure('effect_tooltip', underline=False)
|
|
||||||
|
|
||||||
if not self.current_card_id:
|
|
||||||
self.current_effects.insert(tk.END, "No card selected\n\n", 'effect_name')
|
|
||||||
self.current_effects.insert(tk.END, "Select a card from the Card List tab to view its effects.", 'effect_name')
|
|
||||||
self.current_effects.config(state=tk.DISABLED)
|
|
||||||
return
|
|
||||||
|
|
||||||
level = self.level_var.get()
|
|
||||||
effects = get_effects_at_level(self.current_card_id, level)
|
|
||||||
|
|
||||||
self.current_effects.insert(tk.END, f"━━━ Level {level} ━━━\n\n", 'header')
|
|
||||||
|
|
||||||
if effects:
|
|
||||||
for name, value in effects:
|
|
||||||
# Highlight high values
|
|
||||||
prefix = ""
|
|
||||||
if '%' in str(value):
|
|
||||||
try:
|
|
||||||
num = int(str(value).replace('%', '').replace('+', ''))
|
|
||||||
if num >= 20:
|
|
||||||
prefix = "★ "
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if prefix:
|
|
||||||
self.current_effects.insert(tk.END, prefix, 'highlight')
|
|
||||||
|
|
||||||
# Insert effect name with tooltip tag
|
|
||||||
tag_name = f"tooltip_{name.replace(' ', '_')}"
|
|
||||||
self.current_effects.insert(tk.END, f"{name}: ", ('effect_name', tag_name))
|
|
||||||
|
|
||||||
# Bind tooltip events
|
|
||||||
self.current_effects.tag_bind(tag_name, "<Enter>", lambda e, n=name: self.show_effect_tooltip(e, n))
|
|
||||||
self.current_effects.tag_bind(tag_name, "<Leave>", self.hide_effect_tooltip)
|
|
||||||
|
|
||||||
self.current_effects.insert(tk.END, f"{value}\n", 'effect_value')
|
|
||||||
else:
|
|
||||||
self.current_effects.insert(tk.END, "No effect data available for this level.\n\n", 'effect_name')
|
|
||||||
self.current_effects.insert(tk.END, "Try selecting: Lv 1, 25, 40, or 50", 'effect_name')
|
|
||||||
|
|
||||||
self.current_effects.config(state=tk.DISABLED)
|
|
||||||
|
|
||||||
def show_effect_tooltip(self, event, effect_name):
|
|
||||||
"""Show tooltip for effect"""
|
|
||||||
if effect_name in EFFECT_DESCRIPTIONS:
|
|
||||||
text = EFFECT_DESCRIPTIONS[effect_name]
|
|
||||||
x = event.x_root + 15
|
|
||||||
y = event.y_root + 10
|
|
||||||
|
|
||||||
# Close existing if any
|
|
||||||
self.hide_effect_tooltip(None)
|
|
||||||
|
|
||||||
self.tooltip_window = tk.Toplevel(self)
|
|
||||||
self.tooltip_window.wm_overrideredirect(True)
|
|
||||||
self.tooltip_window.wm_geometry(f"+{x}+{y}")
|
|
||||||
|
|
||||||
label = tk.Label(self.tooltip_window, text=text, justify=tk.LEFT,
|
|
||||||
background=BG_LIGHT, foreground=TEXT_PRIMARY,
|
|
||||||
relief=tk.SOLID, borderwidth=1, font=FONT_SMALL,
|
|
||||||
padx=10, pady=5, wraplength=250)
|
|
||||||
label.pack()
|
|
||||||
|
|
||||||
def hide_effect_tooltip(self, event):
|
|
||||||
"""Hide tooltip"""
|
|
||||||
if hasattr(self, 'tooltip_window') and self.tooltip_window:
|
|
||||||
self.tooltip_window.destroy()
|
|
||||||
self.tooltip_window = None
|
|
||||||
|
|
||||||
def update_progression_table(self):
|
|
||||||
"""Update the effect progression table"""
|
|
||||||
self.effects_tree.delete(*self.effects_tree.get_children())
|
|
||||||
|
|
||||||
if not self.current_card_id:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Get all effects
|
|
||||||
all_effects = get_all_effects(self.current_card_id)
|
|
||||||
|
|
||||||
# Organize by effect name
|
|
||||||
effect_by_level = {}
|
|
||||||
for level, effect_name, effect_value in all_effects:
|
|
||||||
if effect_name not in effect_by_level:
|
|
||||||
effect_by_level[effect_name] = {}
|
|
||||||
effect_by_level[effect_name][level] = effect_value
|
|
||||||
|
|
||||||
# Key levels for the table
|
|
||||||
key_levels = [1, 25, 40, 50]
|
|
||||||
|
|
||||||
# Add rows
|
|
||||||
for effect_name, levels in sorted(effect_by_level.items()):
|
|
||||||
row = [effect_name]
|
|
||||||
for lvl in key_levels:
|
|
||||||
# Find closest level we have data for
|
|
||||||
value = levels.get(lvl, '')
|
|
||||||
if not value:
|
|
||||||
# Try to find nearest
|
|
||||||
for l in sorted(levels.keys()):
|
|
||||||
if l <= lvl:
|
|
||||||
value = levels[l]
|
|
||||||
row.append(value)
|
|
||||||
|
|
||||||
self.effects_tree.insert('', tk.END, values=row)
|
|
||||||
|
|||||||
11
gui/theme.py
11
gui/theme.py
@@ -256,6 +256,17 @@ def configure_styles(root: tk.Tk):
|
|||||||
# WIDGET HELPER FUNCTIONS
|
# WIDGET HELPER FUNCTIONS
|
||||||
# ═══════════════════════════════════════════════════════════════════════════════
|
# ═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
|
||||||
|
def create_styled_entry(parent, textvariable=None, **kwargs):
|
||||||
|
"""Create a styled tk.Entry with modern appearance"""
|
||||||
|
entry = ttk.Entry(
|
||||||
|
parent,
|
||||||
|
textvariable=textvariable,
|
||||||
|
font=FONT_BODY,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
return entry
|
||||||
|
|
||||||
def create_styled_button(parent, text, command=None, style_type='default', **kwargs):
|
def create_styled_button(parent, text, command=None, style_type='default', **kwargs):
|
||||||
"""Create a styled tk.Button with modern appearance"""
|
"""Create a styled tk.Button with modern appearance"""
|
||||||
bg_colors = {
|
bg_colors = {
|
||||||
|
|||||||
Reference in New Issue
Block a user