Adjusted default region dimensions
This commit is contained in:
parent
01da38d05d
commit
2812b96b7c
@ -1,23 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
|
||||||
Project Borealis (Single Region: HP/MP/FP/EXP)
|
|
||||||
==============================================
|
|
||||||
• One region labeled "Player Stats" capturing 4 lines:
|
|
||||||
1) HP: current / max
|
|
||||||
2) MP: current / max
|
|
||||||
3) FP: current / max
|
|
||||||
4) EXP (percentage)
|
|
||||||
|
|
||||||
• HP, MP, FP each have Rich progress bars that stay their assigned color at 100%.
|
|
||||||
• The 4th line (EXP) feeds into historical EXP logic (table + predicted time).
|
|
||||||
• Region is resizable & draggable (edit_mode = True).
|
|
||||||
• Tesseract uses --psm 4 for multi-line segmentation.
|
|
||||||
|
|
||||||
Adjust region.x, region.y, region.w, region.h to match your UI.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
|
||||||
import time
|
import time
|
||||||
import re
|
import re
|
||||||
import pytesseract
|
import pytesseract
|
||||||
@ -26,28 +9,36 @@ from PyQt5.QtCore import Qt, QRect, QPoint, QTimer
|
|||||||
from PyQt5.QtGui import QPainter, QPen, QColor, QFont
|
from PyQt5.QtGui import QPainter, QPen, QColor, QFont
|
||||||
from PIL import Image, ImageGrab, ImageFilter
|
from PIL import Image, ImageGrab, ImageFilter
|
||||||
|
|
||||||
from rich.console import Console
|
from rich.console import Console, Group
|
||||||
from rich.table import Table
|
from rich.table import Table
|
||||||
from rich.progress import Progress, BarColumn, TextColumn
|
from rich.progress import Progress, BarColumn, TextColumn
|
||||||
|
from rich.text import Text
|
||||||
|
from rich.live import Live
|
||||||
|
|
||||||
# ---- [ Global Config ] ----
|
# ---- [ Global Config ] ----
|
||||||
pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"
|
pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"
|
||||||
|
|
||||||
OCR_ENGINE = "Tesseract"
|
OCR_ENGINE = "Tesseract"
|
||||||
POLLING_RATE_MS = 1000
|
POLLING_RATE_MS = 500
|
||||||
MAX_DATA_POINTS = 7
|
MAX_DATA_POINTS = 8
|
||||||
|
|
||||||
DEFAULT_WIDTH = 150
|
DEFAULT_WIDTH = 175
|
||||||
DEFAULT_HEIGHT = 120 # taller to ensure line 4 is captured
|
DEFAULT_HEIGHT = 145
|
||||||
HANDLE_SIZE = 10
|
HANDLE_SIZE = 7
|
||||||
LABEL_HEIGHT = 20
|
LABEL_HEIGHT = 20
|
||||||
|
|
||||||
GREEN_HEADER_STYLE = "bold green"
|
GREEN_HEADER_STYLE = "bold green"
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Helper Functions
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
def format_duration(seconds):
|
def format_duration(seconds):
|
||||||
"""
|
"""
|
||||||
|
INFORMATION PROCESSING:
|
||||||
|
-----------------------
|
||||||
Convert total seconds into hours/min/seconds (e.g., "Xh Ym Zs").
|
Convert total seconds into hours/min/seconds (e.g., "Xh Ym Zs").
|
||||||
Returns '???' if None.
|
Returns '???' if the input is None or invalid.
|
||||||
"""
|
"""
|
||||||
if seconds is None:
|
if seconds is None:
|
||||||
return "???"
|
return "???"
|
||||||
@ -63,6 +54,8 @@ def format_duration(seconds):
|
|||||||
|
|
||||||
def sanitize_experience_string(raw_text):
|
def sanitize_experience_string(raw_text):
|
||||||
"""
|
"""
|
||||||
|
INFORMATION PROCESSING:
|
||||||
|
-----------------------
|
||||||
Extracts a float from raw OCR text for EXP (0-100%).
|
Extracts a float from raw OCR text for EXP (0-100%).
|
||||||
Handles e.g. "25.5682%", "77.8649" etc.
|
Handles e.g. "25.5682%", "77.8649" etc.
|
||||||
"""
|
"""
|
||||||
@ -81,6 +74,8 @@ def sanitize_experience_string(raw_text):
|
|||||||
|
|
||||||
def format_experience_value(value):
|
def format_experience_value(value):
|
||||||
"""
|
"""
|
||||||
|
INFORMATION DISPLAY (formatting):
|
||||||
|
---------------------------------
|
||||||
Format a float 0-100 to XX.XXXX for display in table output.
|
Format a float 0-100 to XX.XXXX for display in table output.
|
||||||
"""
|
"""
|
||||||
if value < 0:
|
if value < 0:
|
||||||
@ -98,8 +93,14 @@ def format_experience_value(value):
|
|||||||
int_part = "00"
|
int_part = "00"
|
||||||
return f"{int_part}.{dec_part}"
|
return f"{int_part}.{dec_part}"
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Region Class
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
class Region:
|
class Region:
|
||||||
"""
|
"""
|
||||||
|
DATA STRUCTURE:
|
||||||
|
---------------
|
||||||
Defines a draggable/resizable screen region for OCR capture.
|
Defines a draggable/resizable screen region for OCR capture.
|
||||||
"""
|
"""
|
||||||
def __init__(self, x, y, label="Region", color=QColor(0,0,255)):
|
def __init__(self, x, y, label="Region", color=QColor(0,0,255)):
|
||||||
@ -129,8 +130,14 @@ class Region:
|
|||||||
QRect(self.x + self.w - HANDLE_SIZE // 2, self.y + self.h - HANDLE_SIZE // 2, HANDLE_SIZE, HANDLE_SIZE), # bottom-right
|
QRect(self.x + self.w - HANDLE_SIZE // 2, self.y + self.h - HANDLE_SIZE // 2, HANDLE_SIZE, HANDLE_SIZE), # bottom-right
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# OverlayCanvas Class
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
class OverlayCanvas(QWidget):
|
class OverlayCanvas(QWidget):
|
||||||
"""
|
"""
|
||||||
|
UI RENDERING LOGIC:
|
||||||
|
-------------------
|
||||||
Renders the overlay & handles region dragging/resizing.
|
Renders the overlay & handles region dragging/resizing.
|
||||||
"""
|
"""
|
||||||
def __init__(self, regions, parent=None):
|
def __init__(self, regions, parent=None):
|
||||||
@ -166,7 +173,7 @@ class OverlayCanvas(QWidget):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if event.button() == Qt.LeftButton:
|
if event.button() == Qt.LeftButton:
|
||||||
# Check topmost region first (reverse if multiple)
|
# Check topmost region first
|
||||||
for region in reversed(self.regions):
|
for region in reversed(self.regions):
|
||||||
# Check each resize handle
|
# Check each resize handle
|
||||||
for i, handle in enumerate(region.resize_handles()):
|
for i, handle in enumerate(region.resize_handles()):
|
||||||
@ -227,11 +234,17 @@ class OverlayCanvas(QWidget):
|
|||||||
self.selected_region = None
|
self.selected_region = None
|
||||||
self.selected_handle = None
|
self.selected_handle = None
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# BorealisOverlay Class
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
class BorealisOverlay(QWidget):
|
class BorealisOverlay(QWidget):
|
||||||
"""
|
"""
|
||||||
Single Region Overlay for Player Stats (HP/MP/FP/EXP)
|
MAIN APPLICATION LOGIC:
|
||||||
|
-----------------------
|
||||||
|
Single Region Overlay for Player Stats (HP/MP/FP/EXP) with OCR scanning.
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self, live=None):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
screen_geo = QApplication.primaryScreen().geometry()
|
screen_geo = QApplication.primaryScreen().geometry()
|
||||||
self.setGeometry(screen_geo)
|
self.setGeometry(screen_geo)
|
||||||
@ -239,7 +252,7 @@ class BorealisOverlay(QWidget):
|
|||||||
self.setAttribute(Qt.WA_TranslucentBackground, True)
|
self.setAttribute(Qt.WA_TranslucentBackground, True)
|
||||||
|
|
||||||
# Single region, with an increased height (120)
|
# Single region, with an increased height (120)
|
||||||
region = Region(250, 50, label="Player Stats")
|
region = Region(250, 50, label="Character Status")
|
||||||
region.h = 120
|
region.h = 120
|
||||||
self.regions = [region]
|
self.regions = [region]
|
||||||
|
|
||||||
@ -252,15 +265,30 @@ class BorealisOverlay(QWidget):
|
|||||||
# Keep history of EXP data
|
# Keep history of EXP data
|
||||||
self.points = []
|
self.points = []
|
||||||
|
|
||||||
|
# We will store a reference to Rich.Live here
|
||||||
|
self.live = live
|
||||||
|
|
||||||
# Timer for periodic OCR scanning
|
# Timer for periodic OCR scanning
|
||||||
self.timer = QTimer(self)
|
self.timer = QTimer(self)
|
||||||
self.timer.timeout.connect(self.collect_ocr_data)
|
self.timer.timeout.connect(self.collect_ocr_data)
|
||||||
self.timer.start(POLLING_RATE_MS)
|
self.timer.start(POLLING_RATE_MS)
|
||||||
|
|
||||||
# ---------------------------------------------------------------------
|
def set_live(self, live):
|
||||||
|
"""
|
||||||
|
Called by main() so we can update the Live object from inside this class.
|
||||||
|
"""
|
||||||
|
self.live = live
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
# OCR
|
# OCR
|
||||||
# ---------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
def collect_ocr_data(self):
|
def collect_ocr_data(self):
|
||||||
|
"""
|
||||||
|
INFORMATION GATHERING:
|
||||||
|
----------------------
|
||||||
|
Periodically invoked by QTimer. Captures region screenshot, OCR's it,
|
||||||
|
and triggers the terminal display update.
|
||||||
|
"""
|
||||||
for region in self.regions:
|
for region in self.regions:
|
||||||
if region.visible:
|
if region.visible:
|
||||||
screenshot = ImageGrab.grab(
|
screenshot = ImageGrab.grab(
|
||||||
@ -272,10 +300,15 @@ class BorealisOverlay(QWidget):
|
|||||||
text = pytesseract.image_to_string(processed, config='--psm 4 --oem 1')
|
text = pytesseract.image_to_string(processed, config='--psm 4 --oem 1')
|
||||||
region.data = text.strip()
|
region.data = text.strip()
|
||||||
|
|
||||||
self.display_ocr_data_in_terminal()
|
# Instead of printing directly, we now build a Rich renderable and update Live.
|
||||||
|
if self.live is not None:
|
||||||
|
renderable = self.build_renderable()
|
||||||
|
self.live.update(renderable)
|
||||||
|
|
||||||
def preprocess_image(self, image):
|
def preprocess_image(self, image):
|
||||||
"""
|
"""
|
||||||
|
INFORMATION PROCESSING:
|
||||||
|
-----------------------
|
||||||
Convert to grayscale, scale up, threshold, median filter
|
Convert to grayscale, scale up, threshold, median filter
|
||||||
for improved Tesseract accuracy.
|
for improved Tesseract accuracy.
|
||||||
"""
|
"""
|
||||||
@ -284,11 +317,13 @@ class BorealisOverlay(QWidget):
|
|||||||
thresh = scaled.point(lambda p: p > 200 and 255)
|
thresh = scaled.point(lambda p: p > 200 and 255)
|
||||||
return thresh.filter(ImageFilter.MedianFilter(3))
|
return thresh.filter(ImageFilter.MedianFilter(3))
|
||||||
|
|
||||||
# ---------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
# Parsing
|
# Parsing
|
||||||
# ---------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
def parse_all_stats(self, raw_text):
|
def parse_all_stats(self, raw_text):
|
||||||
"""
|
"""
|
||||||
|
INFORMATION ANALYSIS:
|
||||||
|
---------------------
|
||||||
Expect up to 4 lines: HP, MP, FP, EXP.
|
Expect up to 4 lines: HP, MP, FP, EXP.
|
||||||
Returns dict with keys "hp", "mp", "fp", "exp".
|
Returns dict with keys "hp", "mp", "fp", "exp".
|
||||||
"""
|
"""
|
||||||
@ -328,6 +363,8 @@ class BorealisOverlay(QWidget):
|
|||||||
|
|
||||||
def update_points(self, new_val):
|
def update_points(self, new_val):
|
||||||
"""
|
"""
|
||||||
|
INFORMATION TRACKING:
|
||||||
|
---------------------
|
||||||
Track historical EXP changes for table & predicted time to level.
|
Track historical EXP changes for table & predicted time to level.
|
||||||
"""
|
"""
|
||||||
now = time.time()
|
now = time.time()
|
||||||
@ -343,11 +380,13 @@ class BorealisOverlay(QWidget):
|
|||||||
if len(self.points) > MAX_DATA_POINTS:
|
if len(self.points) > MAX_DATA_POINTS:
|
||||||
self.points.pop(0)
|
self.points.pop(0)
|
||||||
|
|
||||||
# ---------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
# Display
|
# Display Logic
|
||||||
# ---------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
def compute_time_to_100(self):
|
def compute_time_to_100(self):
|
||||||
"""
|
"""
|
||||||
|
INFORMATION PREDICTION:
|
||||||
|
-----------------------
|
||||||
Estimate time to reach 100% from current EXP data.
|
Estimate time to reach 100% from current EXP data.
|
||||||
"""
|
"""
|
||||||
n = len(self.points)
|
n = len(self.points)
|
||||||
@ -376,18 +415,17 @@ class BorealisOverlay(QWidget):
|
|||||||
|
|
||||||
return int(remain / rate_per_s)
|
return int(remain / rate_per_s)
|
||||||
|
|
||||||
def display_ocr_data_in_terminal(self):
|
def build_renderable(self):
|
||||||
"""
|
"""
|
||||||
Clears terminal, prints HP/MP/FP bars, EXP table, predicted time.
|
INFORMATION DISPLAY (Rich):
|
||||||
|
---------------------------
|
||||||
|
Construct a single Rich renderable (Group) that includes:
|
||||||
|
- Title
|
||||||
|
- HP/MP/FP progress bars
|
||||||
|
- Historical EXP table
|
||||||
|
- Predicted time progress bar
|
||||||
"""
|
"""
|
||||||
console = Console()
|
# Gather stats from first region
|
||||||
os.system('cls' if os.name == 'nt' else 'clear')
|
|
||||||
|
|
||||||
# Title
|
|
||||||
console.print("[bold white]Project Borealis[/bold white]")
|
|
||||||
console.print("[dim]Flyff Information Overlay[/dim]\n")
|
|
||||||
|
|
||||||
# Parse stats
|
|
||||||
raw_text = self.regions[0].data
|
raw_text = self.regions[0].data
|
||||||
stats = self.parse_all_stats(raw_text)
|
stats = self.parse_all_stats(raw_text)
|
||||||
hp_cur, hp_max = stats["hp"]
|
hp_cur, hp_max = stats["hp"]
|
||||||
@ -395,48 +433,57 @@ class BorealisOverlay(QWidget):
|
|||||||
fp_cur, fp_max = stats["fp"]
|
fp_cur, fp_max = stats["fp"]
|
||||||
exp_val = stats["exp"]
|
exp_val = stats["exp"]
|
||||||
|
|
||||||
# Show HP / MP / FP bars, forcing each color to remain even at 100%
|
# Update historical EXP points if valid
|
||||||
with Progress(
|
if exp_val is not None:
|
||||||
|
self.update_points(exp_val)
|
||||||
|
current_exp = self.points[-1][1] if self.points else 0.0
|
||||||
|
|
||||||
|
# ---------------------
|
||||||
|
# 1) Title Section
|
||||||
|
# ---------------------
|
||||||
|
title_text = Text("Project Borealis\n", style="bold white")
|
||||||
|
subtitle_text = Text("Flyff Information Overlay\n\n", style="dim")
|
||||||
|
|
||||||
|
# ---------------------
|
||||||
|
# 2) HP / MP / FP Bars
|
||||||
|
# ---------------------
|
||||||
|
bar_progress = Progress(
|
||||||
"{task.description}",
|
"{task.description}",
|
||||||
BarColumn(bar_width=30),
|
BarColumn(bar_width=30),
|
||||||
TextColumn(" {task.completed}/{task.total} ({task.percentage:>5.2f}%)"),
|
TextColumn(" {task.completed}/{task.total} ({task.percentage:>5.2f}%)"),
|
||||||
console=console,
|
|
||||||
transient=False,
|
transient=False,
|
||||||
auto_refresh=True,
|
auto_refresh=False # We'll refresh after all tasks are added
|
||||||
) as progress:
|
)
|
||||||
|
|
||||||
progress.add_task(
|
# HP
|
||||||
"[bold red]HP[/bold red]",
|
hp_task = bar_progress.add_task(
|
||||||
total=hp_max,
|
"[bold red]HP[/bold red]",
|
||||||
completed=hp_cur,
|
total=hp_max,
|
||||||
style="red",
|
completed=hp_cur,
|
||||||
complete_style="red" # remain red at 100%
|
style="red",
|
||||||
)
|
complete_style="red"
|
||||||
progress.add_task(
|
)
|
||||||
"[bold blue]MP[/bold blue]",
|
# MP
|
||||||
total=mp_max,
|
mp_task = bar_progress.add_task(
|
||||||
completed=mp_cur,
|
"[bold blue]MP[/bold blue]",
|
||||||
style="blue",
|
total=mp_max,
|
||||||
complete_style="blue" # remain blue at 100%
|
completed=mp_cur,
|
||||||
)
|
style="blue",
|
||||||
progress.add_task(
|
complete_style="blue"
|
||||||
"[bold green]FP[/bold green]",
|
)
|
||||||
total=fp_max,
|
# FP
|
||||||
completed=fp_cur,
|
fp_task = bar_progress.add_task(
|
||||||
style="green",
|
"[bold green]FP[/bold green]",
|
||||||
complete_style="green" # remain green at 100%
|
total=fp_max,
|
||||||
)
|
completed=fp_cur,
|
||||||
|
style="green",
|
||||||
|
complete_style="green"
|
||||||
|
)
|
||||||
|
bar_progress.refresh()
|
||||||
|
|
||||||
progress.refresh()
|
# ---------------------
|
||||||
progress.stop()
|
# 3) Historical EXP Table
|
||||||
|
# ---------------------
|
||||||
console.print() # blank line after bars
|
|
||||||
|
|
||||||
# If we have an EXP value, update historical data
|
|
||||||
if exp_val is not None:
|
|
||||||
self.update_points(exp_val)
|
|
||||||
|
|
||||||
# Build the Historical EXP table
|
|
||||||
table = Table(show_header=True, header_style=GREEN_HEADER_STYLE, style=None)
|
table = Table(show_header=True, header_style=GREEN_HEADER_STYLE, style=None)
|
||||||
table.add_column("Historical EXP", justify="center", style="green")
|
table.add_column("Historical EXP", justify="center", style="green")
|
||||||
table.add_column("Time Since Last Kill", justify="center", style="green")
|
table.add_column("Time Since Last Kill", justify="center", style="green")
|
||||||
@ -454,9 +501,9 @@ class BorealisOverlay(QWidget):
|
|||||||
for i in range(1, n):
|
for i in range(1, n):
|
||||||
t_cur, v_cur = self.points[i]
|
t_cur, v_cur = self.points[i]
|
||||||
t_prev, v_prev = self.points[i - 1]
|
t_prev, v_prev = self.points[i - 1]
|
||||||
|
|
||||||
delta_v = v_cur - v_prev
|
delta_v = v_cur - v_prev
|
||||||
delta_str = f"{delta_v:+.4f}%"
|
delta_str = f"{delta_v:+.4f}%"
|
||||||
|
|
||||||
exp_main = format_experience_value(v_cur)
|
exp_main = format_experience_value(v_cur)
|
||||||
exp_str = f"[green]{exp_main}%[/green] [dim]({delta_str})[/dim]"
|
exp_str = f"[green]{exp_main}%[/green] [dim]({delta_str})[/dim]"
|
||||||
|
|
||||||
@ -473,34 +520,62 @@ class BorealisOverlay(QWidget):
|
|||||||
|
|
||||||
table.add_row(exp_str, t_since_str, avg_exp_str, avg_time_str)
|
table.add_row(exp_str, t_since_str, avg_exp_str, avg_time_str)
|
||||||
|
|
||||||
console.print(table)
|
# ---------------------
|
||||||
console.print() # blank line
|
# 4) Predicted Time to Level
|
||||||
|
# ---------------------
|
||||||
# Predicted time to level
|
|
||||||
current_exp = self.points[-1][1] if self.points else 0.0
|
|
||||||
secs_left = self.compute_time_to_100()
|
secs_left = self.compute_time_to_100()
|
||||||
time_str = format_duration(secs_left)
|
time_str = format_duration(secs_left)
|
||||||
|
|
||||||
with Progress(
|
time_bar = Progress(
|
||||||
TextColumn("[bold white]Predicted Time to Level:[/bold white] "),
|
TextColumn("[bold white]Predicted Time to Level:[/bold white] "),
|
||||||
BarColumn(bar_width=30, complete_style="magenta"),
|
BarColumn(bar_width=30, complete_style="magenta"),
|
||||||
TextColumn(" [green]{task.percentage:>5.2f}%[/green] "),
|
TextColumn(" [green]{task.percentage:>5.2f}%[/green] "),
|
||||||
TextColumn(f"[magenta]{time_str}[/magenta] until 100%", justify="right"),
|
TextColumn(f"[magenta]{time_str}[/magenta] until 100%", justify="right"),
|
||||||
console=console,
|
|
||||||
transient=False,
|
transient=False,
|
||||||
) as progress:
|
auto_refresh=False
|
||||||
progress.add_task("", total=100, completed=current_exp)
|
)
|
||||||
progress.refresh()
|
t_task = time_bar.add_task("", total=100, completed=current_exp)
|
||||||
|
time_bar.refresh()
|
||||||
|
|
||||||
|
# Combine everything into a Rich Group
|
||||||
|
# Title + Subtitle + HP/MP/FP Progress + Table + Time Bar
|
||||||
|
return Group(
|
||||||
|
title_text,
|
||||||
|
subtitle_text,
|
||||||
|
bar_progress, # HP/MP/FP
|
||||||
|
table,
|
||||||
|
time_bar # predicted-time progress
|
||||||
|
)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# main()
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""
|
"""
|
||||||
Launches the PyQt5 overlay, starts the event loop.
|
LAUNCH SEQUENCE:
|
||||||
|
---------------
|
||||||
|
1) Create QApplication.
|
||||||
|
2) Create BorealisOverlay Window.
|
||||||
|
3) Use Rich Live to continuously update terminal output with no flicker.
|
||||||
|
4) Start PyQt event loop.
|
||||||
"""
|
"""
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
window = BorealisOverlay()
|
window = BorealisOverlay() # We'll inject Live momentarily
|
||||||
|
|
||||||
window.setWindowTitle("Project Borealis Overlay (HP/MP/FP/EXP)")
|
window.setWindowTitle("Project Borealis Overlay (HP/MP/FP/EXP)")
|
||||||
window.show()
|
window.show()
|
||||||
sys.exit(app.exec_())
|
|
||||||
|
console = Console()
|
||||||
|
|
||||||
|
# Use a Live context manager so we can do partial updates
|
||||||
|
with Live(console=console, refresh_per_second=4) as live:
|
||||||
|
# Pass the live object to our BorealisOverlay so it can call live.update()
|
||||||
|
window.set_live(live)
|
||||||
|
# Run the PyQt event loop (blocking)
|
||||||
|
exit_code = app.exec_()
|
||||||
|
|
||||||
|
sys.exit(exit_code)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user