Standardize Win Probability donut alignment, integrate custom hex colors, and add HTML Browser Source export for Rookies
This commit is contained in:
parent
2ec2f821e4
commit
f9db06d1c2
2 changed files with 117 additions and 16 deletions
|
|
@ -1420,34 +1420,131 @@ class DashLeagueGUI:
|
||||||
|
|
||||||
rookies = rank_rookies_by_tag(season, tag)
|
rookies = rank_rookies_by_tag(season, tag)
|
||||||
|
|
||||||
|
# 1. Text display for the GUI window
|
||||||
lines = []
|
lines = []
|
||||||
lines.append(f"ROOKIE LEADERBOARD — Season {season}")
|
lines.append(f"ROOKIE LEADERBOARD — Season {season}")
|
||||||
lines.append("Rookies: < 50 maps and < 1000 kills.")
|
lines.append("Rookies: < 50 maps and < 1000 kills.")
|
||||||
lines.append("")
|
lines.append("")
|
||||||
# Updated Header
|
|
||||||
lines.append(f"{'Rank':<5} {'Name':<18} {'Team':<12} {'Score':<10} {'KD':<6} {'Maps':<6} {'Kills':<8}")
|
lines.append(f"{'Rank':<5} {'Name':<18} {'Team':<12} {'Score':<10} {'KD':<6} {'Maps':<6} {'Kills':<8}")
|
||||||
lines.append("-" * 75)
|
lines.append("-" * 75)
|
||||||
|
|
||||||
for r in rookies:
|
for r in rookies:
|
||||||
# Format thousands for score (e.g. 96,107)
|
|
||||||
score_str = f"{int(r['score']):,}"
|
score_str = f"{int(r['score']):,}"
|
||||||
kd_str = f"{r['kd']:.2f}"
|
kd_str = f"{r['kd']:.2f}"
|
||||||
maps_str = f"{int(r['maps'])}"
|
maps_str = f"{int(r['maps'])}"
|
||||||
kills_str = f"{int(r['kills'])}"
|
kills_str = f"{int(r['kills'])}"
|
||||||
|
|
||||||
lines.append(f"{r['rank']:<5} {r['name']:<18} {r['team']:<12} {score_str:<10} {kd_str:<6} {maps_str:<6} {kills_str:<8}")
|
lines.append(f"{r['rank']:<5} {r['name']:<18} {r['team']:<12} {score_str:<10} {kd_str:<6} {maps_str:<6} {kills_str:<8}")
|
||||||
|
|
||||||
text = "\n".join(lines)
|
text = "\n".join(lines)
|
||||||
|
|
||||||
win = tk.Toplevel(self.root)
|
win = tk.Toplevel(self.root)
|
||||||
win.title("Rookie Standings")
|
win.title("Rookie Standings")
|
||||||
win.geometry("800x550")
|
win.geometry("800x600")
|
||||||
|
|
||||||
output = tk.Text(win, wrap="none", font=("Courier", 10))
|
output = tk.Text(win, wrap="none", font=("Courier", 10))
|
||||||
output.pack(expand=True, fill="both", padx=10, pady=10)
|
output.pack(expand=True, fill="both", padx=10, pady=10)
|
||||||
output.insert(tk.END, text)
|
output.insert(tk.END, text)
|
||||||
output.config(state="disabled")
|
output.config(state="disabled")
|
||||||
|
|
||||||
|
# 2. HTML Export function for OBS Browser Source
|
||||||
|
def export_html():
|
||||||
|
html_rows = ""
|
||||||
|
for r in rookies:
|
||||||
|
html_rows += f"""
|
||||||
|
<tr>
|
||||||
|
<td class="rank">#{r['rank']}</td>
|
||||||
|
<td class="name">{r['name']}</td>
|
||||||
|
<td class="team">{r['team']}</td>
|
||||||
|
<td class="score">{int(r['score']):,}</td>
|
||||||
|
<td class="kd">{r['kd']:.2f}</td>
|
||||||
|
<td class="kills">{int(r['kills'])}</td>
|
||||||
|
<td class="maps">{int(r['maps'])}</td>
|
||||||
|
</tr>
|
||||||
|
"""
|
||||||
|
|
||||||
|
html_content = f"""
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
body {{
|
||||||
|
background-color: rgba(10, 10, 15, 0.95);
|
||||||
|
color: #ffffff;
|
||||||
|
font-family: 'Segoe UI', Arial, sans-serif;
|
||||||
|
margin: 30px;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 2px solid #0d86f4;
|
||||||
|
}}
|
||||||
|
h1 {{
|
||||||
|
text-align: center;
|
||||||
|
color: #0d86f4;
|
||||||
|
font-size: 32px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 3px;
|
||||||
|
}}
|
||||||
|
.subtitle {{
|
||||||
|
text-align: center;
|
||||||
|
color: #aaaaaa;
|
||||||
|
font-size: 16px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}}
|
||||||
|
table {{
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: 20px;
|
||||||
|
}}
|
||||||
|
th {{
|
||||||
|
border-bottom: 4px solid #f40d35;
|
||||||
|
padding: 15px;
|
||||||
|
text-align: left;
|
||||||
|
color: #aaaaaa;
|
||||||
|
font-weight: bold;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}}
|
||||||
|
td {{
|
||||||
|
padding: 15px;
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
}}
|
||||||
|
.rank {{ font-weight: bold; color: #0d86f4; width: 8%; }}
|
||||||
|
.name {{ font-weight: bold; width: 25%; }}
|
||||||
|
.team {{ color: #aaaaaa; width: 17%; }}
|
||||||
|
.score {{ text-align: right; width: 15%; font-family: monospace; font-weight: bold; }}
|
||||||
|
.kd {{ text-align: right; width: 10%; font-family: monospace; }}
|
||||||
|
.kills {{ text-align: right; width: 10%; font-family: monospace; color: #f40d35; }}
|
||||||
|
.maps {{ text-align: right; width: 15%; font-family: monospace; }}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Rookie Leaderboard</h1>
|
||||||
|
<div class="subtitle">Season {season} | < 50 maps and < 1000 kills</div>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th class="rank">Rank</th>
|
||||||
|
<th class="name">Name</th>
|
||||||
|
<th class="team">Team</th>
|
||||||
|
<th class="score">Score</th>
|
||||||
|
<th class="kd">KD</th>
|
||||||
|
<th class="kills">Kills</th>
|
||||||
|
<th class="maps">Maps</th>
|
||||||
|
</tr>
|
||||||
|
{html_rows}
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""
|
||||||
|
# Save to exports folder
|
||||||
|
html_path = os.path.join(OBS_EXPORT_DIR, "rookie_leaderboard.html")
|
||||||
|
with open(html_path, "w", encoding="utf-8") as f:
|
||||||
|
f.write(html_content)
|
||||||
|
|
||||||
|
self.set_status("Exported Rookie HTML (incl. Kills)")
|
||||||
|
messagebox.showinfo("Exported", f"HTML updated\nLocation: {html_path}")
|
||||||
|
|
||||||
|
# Add button to pop-up window
|
||||||
|
ttk.Button(win, text="Export HTML for OBS Browser Source", command=export_html).pack(pady=10)
|
||||||
|
|
||||||
|
|
||||||
def export_all_obs_files(self):
|
def export_all_obs_files(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,7 @@ def generate_team_dna(rosterA, rosterB, nameA, nameB):
|
||||||
img.save(DNA_PATH)
|
img.save(DNA_PATH)
|
||||||
|
|
||||||
def draw_vs_donut(draw, center, radius, valA, valB, colorA, colorB, label):
|
def draw_vs_donut(draw, center, radius, valA, valB, colorA, colorB, label):
|
||||||
"""Draws a split donut showing relative strength between two teams."""
|
"""Draws a split donut showing relative strength, matching screen sides perfectly."""
|
||||||
cx, cy = center
|
cx, cy = center
|
||||||
width = 35
|
width = 35
|
||||||
total = valA + valB
|
total = valA + valB
|
||||||
|
|
@ -171,23 +171,27 @@ def draw_vs_donut(draw, center, radius, valA, valB, colorA, colorB, label):
|
||||||
valA, valB = 50, 50
|
valA, valB = 50, 50
|
||||||
total = 100
|
total = 100
|
||||||
|
|
||||||
# Percentages of the circle
|
|
||||||
pctA = valA / total
|
pctA = valA / total
|
||||||
|
|
||||||
# Background circle
|
# Draw background circle
|
||||||
draw.ellipse([cx-radius, cy-radius, cx+radius, cy+radius], outline=(40, 40, 45), width=width)
|
draw.ellipse([cx-radius, cy-radius, cx+radius, cy+radius], outline=(40, 40, 45), width=width)
|
||||||
|
|
||||||
# Arcs
|
# --- SWAP CORRECTION ---
|
||||||
start_angle = -90
|
# We start at 90 degrees (6 o'clock) and draw clockwise.
|
||||||
split_angle = start_angle + (360 * pctA)
|
# This aligns Team A (Blue, Left) with the Left Side of the donut,
|
||||||
|
# and Team B (Red, Right) with the Right Side.
|
||||||
|
startA = 90
|
||||||
|
endA = startA + (360 * pctA)
|
||||||
|
|
||||||
# Blue Arc (Team A)
|
# Blue Arc (Team A - Left side)
|
||||||
draw.arc([cx-radius, cy-radius, cx+radius, cy+radius], start=start_angle, end=split_angle, fill=colorA, width=width)
|
draw.arc([cx-radius, cy-radius, cx+radius, cy+radius], start=startA, end=endA, fill=colorA, width=width)
|
||||||
# Red Arc (Team B)
|
# Red Arc (Team B - Right side)
|
||||||
draw.arc([cx-radius, cy-radius, cx+radius, cy+radius], start=split_angle, end=start_angle + 360, fill=colorB, width=width)
|
draw.arc([cx-radius, cy-radius, cx+radius, cy+radius], start=endA, end=startA + 360, fill=colorB, width=width)
|
||||||
|
|
||||||
# Center Text
|
# Center Text
|
||||||
draw.text((cx, cy), f"{int((valA/total)*100)}% | {int((valB/total)*100)}%", font=get_font(45), fill=(255, 255, 255), anchor="mm")
|
pctA_display = int((valA/total)*100)
|
||||||
|
pctB_display = 100 - pctA_display
|
||||||
|
draw.text((cx, cy), f"{pctA_display}% | {pctB_display}%", font=get_font(45), fill=(255, 255, 255), anchor="mm")
|
||||||
draw.text((cx, cy + radius + 60), label, font=get_font(40), fill=(180, 180, 180), anchor="mm")
|
draw.text((cx, cy + radius + 60), label, font=get_font(40), fill=(180, 180, 180), anchor="mm")
|
||||||
|
|
||||||
def generate_win_probability(rosterA, rosterB, nameA, nameB):
|
def generate_win_probability(rosterA, rosterB, nameA, nameB):
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue