From 70e2b225e82c478a08fff5596c3de7ac93dc1d0a Mon Sep 17 00:00:00 2001 From: Vincent 'Philaeux' Lamotte Date: Fri, 4 Aug 2023 19:10:11 +0200 Subject: [PATCH] Progression on the settings ui --- src/dota_notes/app_dota.py | 45 +- src/dota_notes/data/database.py | 6 - .../{application_state.py => game_state.py} | 2 +- src/dota_notes/data/messages.py | 42 + src/dota_notes/data/settings.py | 23 + src/dota_notes/dota_notes.py | 37 +- src/dota_notes/ui/app_qt.py | 91 +- .../ui/gamestate_integration_notes.cfg | 17 + src/dota_notes/ui/main_window.py | 19 +- src/dota_notes/ui/ui_main_window.ui | 6222 +++++++++-------- 10 files changed, 3619 insertions(+), 2885 deletions(-) rename src/dota_notes/data/{application_state.py => game_state.py} (91%) create mode 100644 src/dota_notes/data/messages.py create mode 100644 src/dota_notes/data/settings.py create mode 100644 src/dota_notes/ui/gamestate_integration_notes.cfg diff --git a/src/dota_notes/app_dota.py b/src/dota_notes/app_dota.py index f8ee561..db62c9e 100644 --- a/src/dota_notes/app_dota.py +++ b/src/dota_notes/app_dota.py @@ -3,6 +3,10 @@ from dota2.msg import EDOTAGCMsg import logging + +from dota_notes.data.messages import Message, MessageType, MessageServerIdResponse, MessageConSatus, \ + MessageServerIdRequest + logging.basicConfig(format='[%(asctime)s] %(levelname)s %(name)s: %(message)s', level=logging.DEBUG) @@ -12,40 +16,57 @@ def dota_process(username, password, match_id_in_queue, server_id_out_queue): class DotaApp: - def __init__(self, username, password, user_steam_id_in_queue, server_id_out_queue): + def __init__(self, username, password, message_queue_dota, message_queue_qt): self.username = username self.password = password - self.user_steam_id_in_queue = user_steam_id_in_queue - self.server_id_out_queue = server_id_out_queue + self.message_queue_dota = message_queue_dota + self.message_queue_qt = message_queue_qt + self.message_buffer_queue = [] self.steam = SteamClient() self.dota = Dota2Client(self.steam) self.dota_ready = False self.match_id = 0 - self.currentPage = 0 self.keep_running = True - self.steam.on('logged_on', self.start_dota) + self.steam.on('logged_on', self.on_logged_on) self.dota.on('ready', self.do_dota_stuff) self.dota.on('disconnected', self.on_disconnect) self.dota.on(EDOTAGCMsg.EMsgGCSpectateFriendGameResponse, self.on_spectate_response) - def start_dota(self): + def on_logged_on(self): + self.message_queue_qt.put(Message(MessageType.CLIENTS_STATUS, MessageConSatus("On", "Try"))) self.dota.launch() def do_dota_stuff(self): + self.message_queue_qt.put(Message(MessageType.CLIENTS_STATUS, MessageConSatus("On", "On"))) self.dota_ready = True def on_disconnect(self): - self.keep_running = False + self.message_queue_qt.put(Message(MessageType.CLIENTS_STATUS, MessageConSatus("Off", "Off"))) def on_spectate_response(self, response): - self.server_id_out_queue.put(response.server_steamid) + self.message_queue_qt.put(Message(MessageType.SERVER_ID_RESPONSE, + MessageServerIdResponse(response.server_steamid))) - def run(self): + def connect(self): + self.message_queue_qt.put(Message(MessageType.CLIENTS_STATUS, MessageConSatus("Try", "Off"))) self.steam.login(username=self.username, password=self.password) + + def run(self): while self.keep_running: - if self.dota_ready and not self.user_steam_id_in_queue.empty(): - user_steam_id = self.user_steam_id_in_queue.get(block=False) - self.dota.send(EDOTAGCMsg.EMsgGCSpectateFriendGame, {'steam_id': int(user_steam_id)}) + if not self.message_queue_dota.empty(): + message = self.message_queue_dota.get(block=False) + if message.message_type == MessageType.CLIENTS_CONNECT: + self.connect() + else: + self.message_buffer_queue.append(message) + if self.dota_ready and len(self.message_buffer_queue) > 0: + message = self.message_buffer_queue.pop(0) + if message.message_type == MessageType.SERVER_ID_REQUEST: + message_request: MessageServerIdRequest = message.payload + self.dota.send(EDOTAGCMsg.EMsgGCSpectateFriendGame, {'steam_id': int(message_request.account_id)}) self.steam.sleep(1) + + def stop(self): + self.keep_running = False diff --git a/src/dota_notes/data/database.py b/src/dota_notes/data/database.py index 0350333..3b0bef6 100644 --- a/src/dota_notes/data/database.py +++ b/src/dota_notes/data/database.py @@ -20,12 +20,6 @@ def __init__(self): with Session(self.engine) as session: if session.get(Setting, "version") is None: session.add(Setting("version", "1")) - if session.query(Setting).filter_by(key="steam_user").one_or_none() is None: - session.add(Setting("steam_user", "")) - if session.query(Setting).filter_by(key="steam_password").one_or_none() is None: - session.add(Setting("steam_password", "")) - if session.query(Setting).filter_by(key="steam_api_key").one_or_none() is None: - session.add(Setting("steam_api_key", "")) session.commit() diff --git a/src/dota_notes/data/application_state.py b/src/dota_notes/data/game_state.py similarity index 91% rename from src/dota_notes/data/application_state.py rename to src/dota_notes/data/game_state.py index 73e8086..bebb367 100644 --- a/src/dota_notes/data/application_state.py +++ b/src/dota_notes/data/game_state.py @@ -3,7 +3,7 @@ from dota_notes.data.player_state import PlayerState -class ApplicationState(QObject): +class GameState(QObject): match_id = 0 server_id = 0 players = [] diff --git a/src/dota_notes/data/messages.py b/src/dota_notes/data/messages.py new file mode 100644 index 0000000..735a7cb --- /dev/null +++ b/src/dota_notes/data/messages.py @@ -0,0 +1,42 @@ +from typing import Optional +from enum import Enum + + +class MessageType(Enum): + UNKNOWN = 0 + CLIENTS_STATUS = 1 + CLIENTS_CONNECT = 2 + SERVER_ID_REQUEST = 3 + SERVER_ID_RESPONSE = 4 + + +class Message: + message_type: MessageType = MessageType.UNKNOWN + payload: Optional[object] + + def __init__(self, message_type: MessageType, payload: Optional[object] = None): + self.message_type = message_type + self.payload = payload + + +class MessageConSatus: + steam: str + dota: str + + def __init__(self, steam: str, dota: str): + self.steam = steam + self.dota = dota + + +class MessageServerIdRequest: + account_id: str + + def __init__(self, account_id: str): + self.account_id = account_id + + +class MessageServerIdResponse: + server_id: int + + def __init__(self, server_id: int): + self.server_id = server_id diff --git a/src/dota_notes/data/settings.py b/src/dota_notes/data/settings.py new file mode 100644 index 0000000..667d075 --- /dev/null +++ b/src/dota_notes/data/settings.py @@ -0,0 +1,23 @@ +from dota_notes.data.database import Setting + + +class Settings: + + gsi_port: int = 58765 + software_mode: str = "Client" + proxy_url: str = "https://dota-notes.the-cluster.org" + proxy_api_key: str = "" + steam_user: str = "" + steam_password: str = "" + steam_api_key: str = "" + + TO_IMPORT_EXPORT = ["software_mode", "proxy_url", "proxy_api_key", "steam_user", "steam_password", "steam_api_key"] + + def import_from_database(self, session): + + for at in self.TO_IMPORT_EXPORT: + row = session.get(Setting, at) + if row is not None: + setattr(self, at, row.value) + else: + session.add(Setting(at, getattr(self, at))) diff --git a/src/dota_notes/dota_notes.py b/src/dota_notes/dota_notes.py index 55ffe57..2cea66b 100644 --- a/src/dota_notes/dota_notes.py +++ b/src/dota_notes/dota_notes.py @@ -1,10 +1,11 @@ import multiprocessing import sys -from dota_notes.data.application_state import ApplicationState +from dota_notes.data.game_state import GameState from dota_notes.data.database import Database, Setting from dota_notes.app_flask import flask_process from dota_notes.app_dota import dota_process +from dota_notes.data.settings import Settings from dota_notes.ui.app_qt import QtApp from sqlalchemy.orm import Session @@ -12,39 +13,29 @@ class DotaNotes: def __init__(self): - self.state = ApplicationState() + self.state = GameState() + self.database = Database() + self.settings = Settings() + with Session(self.database.engine) as session: + self.settings.import_from_database(session) + session.commit() self.match_information_from_gsi = multiprocessing.Queue() - self.user_steam_id_to_dota = multiprocessing.Queue() - self.server_id_from_dota = multiprocessing.Queue() - self.database = Database() + self.message_queue_dota = multiprocessing.Queue() + self.message_queue_qt = multiprocessing.Queue() self.app_qt = QtApp(self) - self.steam_api_key = "" - def run(self): # Web Server - app_flask = multiprocessing.Process(target=flask_process, args=(58765, self.match_information_from_gsi,)) + app_flask = multiprocessing.Process(target=flask_process, args=(self.settings.gsi_port, + self.match_information_from_gsi,)) app_flask.start() # Dota client - steam_username = "" - steam_password = "" - self.steam_api_key = "" - with Session(self.database.engine) as session: - row = session.get(Setting, "steam_user") - if row is not None: - steam_username = row.value - row = session.get(Setting, "steam_password") - if row is not None: - steam_password = row.value - row = session.get(Setting, "steam_api_key") - if row is not None: - self.steam_api_key = row.value - app_dota = multiprocessing.Process( target=dota_process, - args=(steam_username, steam_password, self.user_steam_id_to_dota, self.server_id_from_dota,) + args=(self.settings.steam_user, self.settings.steam_password, self.message_queue_dota, + self.message_queue_qt,) ) app_dota.start() diff --git a/src/dota_notes/ui/app_qt.py b/src/dota_notes/ui/app_qt.py index 0ad6577..3cde085 100644 --- a/src/dota_notes/ui/app_qt.py +++ b/src/dota_notes/ui/app_qt.py @@ -7,13 +7,14 @@ from sqlalchemy.orm import Session from dota_notes.data.database import Setting, Player +from dota_notes.data.messages import Message, MessageType, MessageServerIdResponse, MessageConSatus, MessageServerIdRequest from dota_notes.helpers import get_game_live_stats from dota_notes.ui.main_window import MainWindow class QtApp: - def __init__(self, d2notes): - self.d2notes = d2notes + def __init__(self, dota_notes): + self.dota_notes = dota_notes # Build App self.app = QApplication(sys.argv) @@ -21,8 +22,11 @@ def __init__(self, d2notes): self.lastIndexSelected = 0 # Connect actions - self.window.actionSettings.triggered.connect(lambda: print("TODO")) + self.window.actionSettings.triggered.connect(self.on_open_settings) self.window.actionExit.triggered.connect(self.window.close) + self.window.buttonSettingsSave.clicked.connect(self.on_settings_save) + self.window.buttonSettingsCancel.clicked.connect(self.on_settings_cancel) + self.window.buttonConnect.clicked.connect(self.on_connect_client) self.window.buttonBububu.clicked.connect(lambda: self.window.inputSteamId.setText("76561198066647717")) self.window.buttonBulldog.clicked.connect(lambda: self.window.inputSteamId.setText("76561198053098358")) self.window.buttonGrubby.clicked.connect(lambda: self.window.inputSteamId.setText("76561198809738927")) @@ -33,13 +37,10 @@ def __init__(self, d2notes): for i in range(10): getattr(self.window, f"labelPlayer{i}Name").clicked.connect(self.on_label_click) - with Session(self.d2notes.database.engine) as session: + with Session(self.dota_notes.database.engine) as session: last_search = session.get(Setting, "last_search") if last_search is not None: self.window.inputSteamId.setText(last_search.value) - - self.status_message("Ready") - self.window.show() def status_message(self, message, timeout=0): @@ -54,30 +55,51 @@ def run(self): return return_code def process_queues(self): - while not self.d2notes.match_information_from_gsi.empty(): - match_info = self.d2notes.match_information_from_gsi.get(block=False) - if self.d2notes.state.match_id != match_info["match_id"]: - self.d2notes.state.match_id = match_info["match_id"] - self.d2notes.state.server_id = 0 - self.status_message(f"Detected match {self.d2notes.state.match_id!s} from GSI.") - self.update_state_with_gsi(self.d2notes.state, match_info) - self.draw_match_with_state(self.d2notes.state) + while not self.dota_notes.match_information_from_gsi.empty(): + match_info = self.dota_notes.match_information_from_gsi.get(block=False) + if self.dota_notes.state.match_id != match_info["match_id"]: + self.dota_notes.state.match_id = match_info["match_id"] + self.dota_notes.state.server_id = 0 + self.status_message(f"Detected match {self.dota_notes.state.match_id!s} from GSI.") + self.update_state_with_gsi(self.dota_notes.state, match_info) + self.draw_match_with_state(self.dota_notes.state) self.draw_details_with_player(0) - while not self.d2notes.server_id_from_dota.empty(): - server_id = self.d2notes.server_id_from_dota.get(block=False) - if server_id != 0: - self.d2notes.state.server_id = server_id - game_json = get_game_live_stats(self.d2notes.steam_api_key, self.d2notes.state.server_id) - self.update_state_with_json(self.d2notes.state, game_json) - self.update_state_with_database(self.d2notes.state) - self.status_message("Found game info for player " + self.window.inputSteamId.text() + " using WEBAPI.") - self.draw_match_with_state(self.d2notes.state) - self.draw_details_with_player(0) - else: - self.status_message("No game found for player " + self.window.inputSteamId.text()) + while not self.dota_notes.message_queue_qt.empty(): + message: Message = self.dota_notes.message_queue_qt.get(block=False) + if message.message_type == MessageType.SERVER_ID_RESPONSE: + server_id_message: MessageServerIdResponse = message.payload + if server_id_message.server_id != 0: + self.dota_notes.state.server_id = server_id_message.server_id + game_json = get_game_live_stats(self.dota_notes.settings.steam_api_key, self.dota_notes.state.server_id) + self.update_state_with_json(self.dota_notes.state, game_json) + self.update_state_with_database(self.dota_notes.state) + self.status_message("Found game info for player " + self.window.inputSteamId.text() + " using WEBAPI.") + self.draw_match_with_state(self.dota_notes.state) + self.draw_details_with_player(0) + else: + self.status_message("No game found for player " + self.window.inputSteamId.text()) + elif message.message_type == MessageType.CLIENTS_STATUS: + con_status_message: MessageConSatus = message.payload + self.window.draw_connection_status(con_status_message.steam, con_status_message.dota) def on_open_settings(self): - pass + self.window.comboBoxSettingsMode.setCurrentText(self.dota_notes.settings.software_mode) + self.window.lineEditSettingsProxyURL.setText(self.dota_notes.settings.proxy_url) + self.window.lineEditSettingsProxyAPIKey.setText(self.dota_notes.settings.proxy_api_key) + self.window.lineEditSettingsSteamUser.setText(self.dota_notes.settings.steam_user) + self.window.lineEditSettingsSteamPassword.setText(self.dota_notes.settings.steam_password) + self.window.lineEditSettingsSteamAPIKey.setText(self.dota_notes.settings.steam_api_key) + self.window.centralStackedWidget.setCurrentIndex(1) + + def on_settings_save(self): + self.window.centralStackedWidget.setCurrentIndex(0) + + def on_settings_cancel(self): + self.window.centralStackedWidget.setCurrentIndex(0) + + def on_connect_client(self): + self.window.buttonConnect.setVisible(False) + self.dota_notes.message_queue_dota.put(Message(MessageType.CLIENTS_CONNECT)) def on_label_click(self, label_name, label_text): row = 0 @@ -89,7 +111,7 @@ def on_label_click(self, label_name, label_text): def draw_details_with_player(self, player_slot): self.lastIndexSelected = player_slot - player_state = self.d2notes.state.players[player_slot] + player_state = self.dota_notes.state.players[player_slot] self.window.labelDetailsSteamId.setText(str(player_state.steam_id)) self.window.labelDetailsName.setText(player_state.name) self.window.labelDetailsProName.setText( @@ -128,8 +150,9 @@ def draw_match_player(self, player_slot, player_data): def on_search_game(self): if self.window.inputSteamId.text() != "": - self.d2notes.user_steam_id_to_dota.put(self.window.inputSteamId.text()) - with Session(self.d2notes.database.engine) as session: + self.dota_notes.message_queue_dota.put(Message(MessageType.SERVER_ID_REQUEST, + MessageServerIdRequest(self.window.inputSteamId.text()))) + with Session(self.dota_notes.database.engine) as session: last_search = session.query(Setting).filter_by(key="last_search").one_or_none() if last_search is not None: last_search.value = self.window.inputSteamId.text() @@ -166,7 +189,7 @@ def update_state_with_gsi(self, state, match_info): state.players[index].name = player["name"] def update_state_with_database(self, state): - with Session(self.d2notes.database.engine) as session: + with Session(self.dota_notes.database.engine) as session: for player in state.players: if player.steam_id == 0: continue @@ -175,7 +198,7 @@ def update_state_with_database(self, state): Player.import_export(player_db, player) def save_player_details(self): - player_state = self.d2notes.state.players[self.lastIndexSelected] + player_state = self.dota_notes.state.players[self.lastIndexSelected] player_state.pro_name = \ self.window.labelDetailsProName.text() if self.window.labelDetailsProName != "" else None player_state.custom_name = self.window.inputDetailsCustomName.text() @@ -188,7 +211,7 @@ def save_player_details(self): player_state.destroys_items = self.window.checkBoxDetailsDestroysItems.isChecked() player_state.note = self.window.inputDetailsNote.toPlainText() self.draw_match_player(self.lastIndexSelected, player_state) - with Session(self.d2notes.database.engine) as session: + with Session(self.dota_notes.database.engine) as session: player_info = session.get(Player, str(player_state.steam_id)) if player_info is None: player_info = Player.make_from_state(player_state) diff --git a/src/dota_notes/ui/gamestate_integration_notes.cfg b/src/dota_notes/ui/gamestate_integration_notes.cfg new file mode 100644 index 0000000..dfaa5ff --- /dev/null +++ b/src/dota_notes/ui/gamestate_integration_notes.cfg @@ -0,0 +1,17 @@ +"Dota 2 Notes" +{ + "uri" "http://localhost:58765/" + "timeout" "5.0" + "buffer" "0.5" + "throttle" "0.5" + "heartbeat" "30.0" + "data" + { + "buildings" "1" + "events" "1" + "hero" "1" + "map" "1" + "player" "1" + "provider" "1" + } +} diff --git a/src/dota_notes/ui/main_window.py b/src/dota_notes/ui/main_window.py index 7d7c28e..35e6d28 100644 --- a/src/dota_notes/ui/main_window.py +++ b/src/dota_notes/ui/main_window.py @@ -7,18 +7,35 @@ class MainWindow(QMainWindow, Ui_MainWindow): SMURF_CHOICES = ["", "Account Buyer", "Booster", "Main", "Maybe", "Smurf", "Sweaty Smurf"] FLAGS = ["Racist", "Sexist", "Feeder", "GivesUp", "Destroyer"] + MODE_CHOICES = ["Proxy Server", "Client"] def __init__(self): super().__init__() self.setupUi(self) + self.centralStackedWidget.setCurrentIndex(0) for smurf_choice in self.SMURF_CHOICES: self.comboBoxDetailsSmurf.addItem(smurf_choice) + for mode_choice in self.MODE_CHOICES: + self.comboBoxSettingsMode.addItem(mode_choice) for i in range(10): for flag in self.FLAGS: getattr(self, f"labelPlayer{i}Flag{flag}").setVisible(False) + self.draw_connection_status("Off", "Off") + + def draw_connection_status(self, steam: str, dota: str): + possible_status = ["On", "Try", "Off"] for client in ["Steam", "Dota"]: - for status in ["On", "Try", "Off"]: + for status in possible_status: getattr(self, f"label{client}Con{status}").setVisible(False) + if steam not in possible_status or dota not in possible_status: + return + getattr(self, f"labelSteamCon{steam}").setVisible(True) + getattr(self, f"labelDotaCon{dota}").setVisible(True) + + if steam == "Off" and dota == "Off": + self.buttonConnect.setVisible(True) + else: + self.buttonConnect.setVisible(False) diff --git a/src/dota_notes/ui/ui_main_window.ui b/src/dota_notes/ui/ui_main_window.ui index 999a7ed..87f052a 100644 --- a/src/dota_notes/ui/ui_main_window.ui +++ b/src/dota_notes/ui/ui_main_window.ui @@ -22,2816 +22,3422 @@ - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - <html><head/><body><p><span style=" font-weight:600;">Steam</span></p></body></html> - - - - - - - - 0 - 0 - - - - - 20 - 20 - - - - - 20 - 20 - - - - background-color: rgb(245, 66, 66) - - - - - - - - - - - 0 - 0 - - - - - 20 - 20 - - - - - 20 - 20 - - - - background-color: rgb(255, 249, 61) - - - - - - - - - - - 0 - 0 - - - - - 20 - 20 - - - - - 20 - 20 - - - - background-color: rgb(0, 191, 29) - - - - - - - - - - <html><head/><body><p><span style=" font-weight:600;">Dota</span></p></body></html> - - - - - - - - 0 - 0 - - - - - 20 - 20 - - - - - 20 - 20 - - - - background-color: rgb(245, 66, 66) - - - - - - - - - - - 0 - 0 - - - - - 20 - 20 - - - - - 20 - 20 - - - - background-color: rgb(255, 249, 61) - - - - - - - - - - - 0 - 0 - - - - - 20 - 20 - - - - - 20 - 20 - - - - background-color: rgb(0, 191, 29) - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - Bububu - - - - - - - Bulldog - - - - - - - Grubby - - - - - - - Philaeux - - - - - - - s4 - - - - - - - - 100 - 0 - - - - - - - - Search - - - - - - - - - - - - - <html><head/><body><p><span style=" font-weight:600;">Match ID</span></p></body></html> - - - Qt::RichText - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - ....................... - - - - - - - <html><head/><body><p><span style=" font-weight:600;">Server ID</span></p></body></html> - - - Qt::RichText - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - ....................... - - - - - - - - - - QFrame::Raised - - - 1 - - - 1 - - - Qt::Horizontal - - - - - - - - - - - 0 - 0 - - - - - 20 - 40 - - - - - 20 - 40 - - - - background-color: rgb(159, 107, 0) - - - - - - - - - - - 0 - 0 - - - - - 20 - 40 - - - - - 20 - 40 - - - - - - - - - - - - 0 - 0 - - - - - 20 - 40 - - - - - 20 - 40 - - - - background-color: rgb(1, 131, 31) - - - - - - - - - - - 0 - 0 - - - - - 20 - 40 - - - - - 20 - 40 - - - - background-color: rgb(189, 0, 183) - - - - - - - - - - - 0 - 0 - - - - - 20 - 40 - - - - - 20 - 40 - - - - background-color: rgb(248, 245, 10) - - - - - - - - - - - 0 - 0 - - - - - 20 - 40 - - - - - 20 - 40 - - - - background-color: rgb(254, 136, 197) - - - - - - - - - - - 0 - 0 - - - - - 20 - 40 - - - - - 20 - 40 - - - - background-color: rgb(255, 105, 0) - - - - - - - - - - - 0 - 0 - - - - - 20 - 40 - - - - - 20 - 40 - - - - background-color: rgb(48, 116, 249) - - - - - - - - - - - 0 - 0 - - - - - 20 - 40 - - - - - 20 - 40 - - - - background-color: rgb(102, 255, 192) - - - - - - - - - - - - - Qt::AlignCenter - - - - - - - - 0 - 0 - - - - - 20 - 40 - - - - - 20 - 40 - - - - background-color: rgb(162, 179, 73) - - - - - - - - - - - - - - - - :/images/racist.png - - - Qt::AlignCenter - - - - - - - - - - :/images/sexist.png - - - Qt::AlignCenter - - - - - - - - 24 - 24 - - - - - - - :/images/toxic.png - - - true - - - Qt::AlignCenter - - - - - - - - - - :/images/feeder.png - - - Qt::AlignCenter - - - - - - - - - - :/images/givesup.png - - - Qt::AlignCenter - - - - - - - - - - :/images/destroyer.png - - - Qt::AlignCenter - - - - - - - - - - - - - - - - :/images/racist.png - - - Qt::AlignCenter - - - - - - - - - - :/images/sexist.png - - - Qt::AlignCenter - - - - - - - - 24 - 24 - - - - - - - :/images/toxic.png - - - true - - - Qt::AlignCenter - - - - - - - - - - :/images/feeder.png - - - Qt::AlignCenter - - - - - - - - - - :/images/givesup.png - - - Qt::AlignCenter - - - - - - - - - - :/images/destroyer.png - - - Qt::AlignCenter - - - - - - - - - - - - - - - - :/images/racist.png - - - Qt::AlignCenter - - - - - - - - - - :/images/sexist.png - - - Qt::AlignCenter - - - - - - - - 24 - 24 - - - - - - - :/images/toxic.png - - - true - - - Qt::AlignCenter - - - - - - - - - - :/images/feeder.png - - - Qt::AlignCenter - - - - - - - - - - :/images/givesup.png - - - Qt::AlignCenter - - - - - - - - - - :/images/destroyer.png - - - Qt::AlignCenter - - - - - - - - - - - - - - 24 - 24 - - - - - - - :/images/racist.png - - - - - - - - - - :/images/sexist.png - - - - - - - true - - - - 0 - 0 - - - - - 24 - 24 - - - - - - - :/images/toxic.png - - - true - - - Qt::AlignCenter - - - - - - - - - - :/images/feeder.png - - - Qt::AlignCenter - - - - - - - - - - :/images/givesup.png - - - Qt::AlignCenter - - - - - - - - - - :/images/destroyer.png - - - Qt::AlignCenter - - - - - - - - - - - - - - - - :/images/racist.png - - - Qt::AlignCenter - - - - - - - - - - :/images/sexist.png - - - Qt::AlignCenter - - - - - - - - 24 - 24 - - - - - - - :/images/toxic.png - - - true - - - Qt::AlignCenter - - - - - - - - - - :/images/feeder.png - - - Qt::AlignCenter - - - - - - - - - - :/images/givesup.png - - - Qt::AlignCenter - - - - - - - - - - :/images/destroyer.png - - - Qt::AlignCenter - - - - - - - - - - - - - - - - :/images/racist.png - - - Qt::AlignCenter - - - - - - - - - - :/images/sexist.png - - - Qt::AlignCenter - - - - - - - - 24 - 24 - - - - - - - :/images/toxic.png - - - true - - - Qt::AlignCenter - - - - - - - - - - :/images/feeder.png - - - Qt::AlignCenter - - - - - - - - - - :/images/givesup.png - - - Qt::AlignCenter - - - - - - - - - - :/images/destroyer.png - - - Qt::AlignCenter - - - - - - - - - - - - - - - - :/images/racist.png - - - Qt::AlignCenter - - - - - - - - - - :/images/sexist.png - - - Qt::AlignCenter - - - - - - - - 24 - 24 - - - - - - - :/images/toxic.png - - - true - - - Qt::AlignCenter - - - - - - - - - - :/images/feeder.png - - - Qt::AlignCenter - - - - - - - - - - :/images/givesup.png - - - Qt::AlignCenter - - - - - - - - - - :/images/destroyer.png - - - Qt::AlignCenter - - - - - - - - - - - - - - - - :/images/racist.png - - - Qt::AlignCenter - - - - - - - - - - :/images/sexist.png - - - Qt::AlignCenter - - - - - - - - 24 - 24 - - - - - - - :/images/toxic.png - - - true - - - Qt::AlignCenter - - - - - - - - - - :/images/feeder.png - - - Qt::AlignCenter - - - - - - - - - - :/images/givesup.png - - - Qt::AlignCenter - - - - - - - - - - :/images/destroyer.png - - - Qt::AlignCenter - - - - - - - - - - - - - - - - :/images/racist.png - - - Qt::AlignCenter - - - - - - - - - - :/images/sexist.png - - - Qt::AlignCenter - - - - - - - - 24 - 24 - - - - - - - :/images/toxic.png - - - true - - - Qt::AlignCenter - - - - - - - - - - :/images/feeder.png - - - Qt::AlignCenter - - - - - - - - - - :/images/givesup.png - - - Qt::AlignCenter - - - - - - - - - - :/images/destroyer.png - - - Qt::AlignCenter - - - - - - - - - - - - - - - - :/images/racist.png - - - Qt::AlignCenter - - - - - - - - - - :/images/sexist.png - - - Qt::AlignCenter - - - - - - - - 24 - 24 - - - - - - - :/images/toxic.png - - - true - - - Qt::AlignCenter - - - - - - - - - - :/images/feeder.png - - - Qt::AlignCenter - - - - - - - - - - :/images/givesup.png - - - Qt::AlignCenter - - - - - - - - - - :/images/destroyer.png - - - Qt::AlignCenter - - - - - - - - - - 99999 - - - Qt::AlignCenter - - - - - - - 99999 - - - Qt::AlignCenter - - - - - - - - 0 - 40 - - - - - - - - - - - 99999 - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignCenter - - - - - - - - 0 - 0 - - - - - 100 - 0 - - - - <html><head/><body><p><span style=" font-weight:600;">Smurf</span></p></body></html> - - - Qt::RichText - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignCenter - - - - - - - - 0 - 40 - - - - - - - - - - - 99999 - - - Qt::AlignCenter - - - - - - - - 0 - 40 - - - - - - - - - - - - 0 - 40 - - - - - - - - - - - - 0 - 40 - - - - - - - - - - - 99999 - - - Qt::AlignCenter - - - - - - - 99999 - - - Qt::AlignCenter - - - - - - - - 0 - 40 - - - - - - - - - - - 99999 - - - Qt::AlignCenter - - - - - - - - 0 - 40 - - - - - - - - - - - - 0 - 0 - - - - - 50 - 0 - - - - <html><head/><body><p><span style=" font-weight:600;">Games</span></p></body></html> - - - Qt::RichText - - - Qt::AlignCenter - - - - - - - - 0 - 40 - - - - - - - - - - - - 160 - 40 - - - - <html><head/><body><p><span style=" font-weight:600;">Name</span></p></body></html> - - - Qt::RichText - - - Qt::AlignCenter - - - - - - - 99999 - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignCenter - - - - - - - 99999 - - - Qt::AlignCenter - - - - - - - 99999 - - - Qt::AlignCenter - - - - - - - - 0 - 40 - - - - - - - - - - - - 0 - 40 - - - - - - - - - - - Qt::Horizontal - - - - - - - Qt::Horizontal - - - - - - - - - - Qt::AlignCenter - - - - - - - - 0 - 0 - - - - - 140 - 0 - - - - <html><head/><body><p><span style=" font-weight:600;">Flags</span></p></body></html> - - - Qt::AlignCenter - - - - - - - - 0 - 0 - - - - - 20 - 40 - - - - - 20 - 40 - - - - background-color: rgb(99, 218, 250) - - - - - - - - - - - 0 - 0 - - - - - 20 - 40 - - - - - 20 - 40 - - - - - - - - - - - - 0 - 0 - - - - - 20 - 40 - - - - - 20 - 40 - - - - background-color: rgb(48, 116, 249) - - - - - - - - - - - 0 - 0 - - - - - 20 - 40 - - - - - 20 - 40 - - - - background-color: rgb(102, 255, 192) - - - - - - - - - - - 0 - 0 - - - - - 20 - 40 - - - - - 20 - 40 - - - - background-color: rgb(189, 0, 183) - - - - - - - - - - - 0 - 0 - - - - - 20 - 40 - - - - - 20 - 40 - - - - background-color: rgb(248, 245, 10) - - - - - - - - - - - 0 - 0 - - - - - 20 - 40 - - - - - 20 - 40 - - - - background-color: rgb(255, 105, 0) - - - - - - - - - - - 0 - 0 - - - - - 20 - 40 - - - - - 20 - 40 - - - - background-color: rgb(254, 136, 197) - - - - - - - - - - - 0 - 0 - - - - - 20 - 40 - - - - - 20 - 40 - - - - background-color: rgb(162, 179, 73) - - - - - - - - - - - 0 - 0 - - - - - 20 - 40 - - - - - 20 - 40 - - - - background-color: rgb(99, 218, 250) - - - - - - - - - - - 0 - 0 - - - - - 20 - 40 - - - - - 20 - 40 - - - - background-color: rgb(1, 131, 31) - - - - - - - - - - - 0 - 0 - - - - - 20 - 40 - - - - - 20 - 40 - - - - background-color: rgb(159, 107, 0) - - - - - - - - - - - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - 120 - 0 - - - - <html><head/><body><p><span style=" font-weight:600;">Custom Name</span></p></body></html> - - - Qt::RichText - - - Qt::AlignCenter - - - - - - - - 120 - 0 - - - - <html><head/><body><p><span style=" font-weight:600;">Pro Name</span></p></body></html> - - - Qt::RichText - - - Qt::AlignCenter - - - - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - - - - QFrame::Raised - - - 1 - - + + 1 - - Qt::Vertical - - - - - - - - - - - - - - 50 - 16777215 - - - - Qt::LeftToRight - - - Save - - - - - - - - - - - - - Toxic - - - - - - - Racist - - - true - - - false - - - false - - - - - - - Sexist - - - - - - - Feeder - - - - - - - Gives Up - - - - - - - Destroys Item - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - <html><head/><body><p><span style=" font-weight:600;">Steam ID</span></p></body></html> - - - Qt::RichText - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - <html><head/><body><p><span style=" font-weight:600;">In Game Name</span></p></body></html> - - - Qt::RichText - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - - - - - <html><head/><body><p><span style=" font-weight:600;">Smurf</span></p></body></html> - - - Qt::RichText - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - - - - - <html><head/><body><p><span style=" font-weight:600;">Pro Name</span></p></body></html> - - - Qt::RichText - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - <html><head/><body><p><span style=" font-weight:600;">Custom Name</span></p></body></html> - - - Qt::RichText - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - <html><head/><body><p><span style=" font-weight:600;">Note</span></p></body></html> - - - Qt::RichText - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - false - - - - - - 9 - - - - + + + + + 0 + 0 + 1282 + 741 + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Steam</span></p></body></html> + + + + + + + + 0 + 0 + + + + + 20 + 20 + + + + + 20 + 20 + + + + Disconnected + + + background-color: rgb(245, 66, 66) + + + + + + + + + + + 0 + 0 + + + + + 20 + 20 + + + + + 20 + 20 + + + + Connecting + + + background-color: rgb(255, 249, 61) + + + + + + + + + + + 0 + 0 + + + + + 20 + 20 + + + + + 20 + 20 + + + + Connected + + + background-color: rgb(0, 191, 29) + + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Dota</span></p></body></html> + + + + + + + + 0 + 0 + + + + + 20 + 20 + + + + + 20 + 20 + + + + Disconnected + + + background-color: rgb(245, 66, 66) + + + + + + + + + + + 0 + 0 + + + + + 20 + 20 + + + + + 20 + 20 + + + + Connecting + + + background-color: rgb(255, 249, 61) + + + + + + + + + + + 0 + 0 + + + + + 20 + 20 + + + + + 20 + 20 + + + + Connected + + + background-color: rgb(0, 191, 29) + + + + + + + + + + Connect + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + Bububu + + + + + + + Bulldog + + + + + + + Grubby + + + + + + + Philaeux + + + + + + + s4 + + + + + + + + 100 + 0 + + + + + + + + Search + + + + + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Match ID</span></p></body></html> + + + Qt::RichText + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + ....................... + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Server ID</span></p></body></html> + + + Qt::RichText + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + ....................... + + + + + + + + + + QFrame::Raised + + + 1 + + + 1 + + + Qt::Horizontal + + + + + + + + + + + 0 + 0 + + + + + 20 + 40 + + + + + 20 + 40 + + + + background-color: rgb(159, 107, 0) + + + + + + + + + + + 0 + 0 + + + + + 20 + 40 + + + + + 20 + 40 + + + + + + + + + + + + 0 + 0 + + + + + 20 + 40 + + + + + 20 + 40 + + + + background-color: rgb(1, 131, 31) + + + + + + + + + + + 0 + 0 + + + + + 20 + 40 + + + + + 20 + 40 + + + + background-color: rgb(189, 0, 183) + + + + + + + + + + + 0 + 0 + + + + + 20 + 40 + + + + + 20 + 40 + + + + background-color: rgb(248, 245, 10) + + + + + + + + + + + 0 + 0 + + + + + 20 + 40 + + + + + 20 + 40 + + + + background-color: rgb(254, 136, 197) + + + + + + + + + + + 0 + 0 + + + + + 20 + 40 + + + + + 20 + 40 + + + + background-color: rgb(255, 105, 0) + + + + + + + + + + + 0 + 0 + + + + + 20 + 40 + + + + + 20 + 40 + + + + background-color: rgb(48, 116, 249) + + + + + + + + + + + 0 + 0 + + + + + 20 + 40 + + + + + 20 + 40 + + + + background-color: rgb(102, 255, 192) + + + + + + + + + + + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 20 + 40 + + + + + 20 + 40 + + + + background-color: rgb(162, 179, 73) + + + + + + + + + + + + + Racist + + + + + + :/images/racist.png + + + Qt::AlignCenter + + + + + + + Sexist + + + + + + :/images/sexist.png + + + Qt::AlignCenter + + + + + + + + 24 + 24 + + + + Toxic + + + + + + :/images/toxic.png + + + true + + + Qt::AlignCenter + + + + + + + Feeder + + + + + + :/images/feeder.png + + + Qt::AlignCenter + + + + + + + Gives Up + + + + + + :/images/givesup.png + + + Qt::AlignCenter + + + + + + + Destroys Items + + + + + + :/images/destroyer.png + + + Qt::AlignCenter + + + + + + + + + + + + + Racist + + + + + + :/images/racist.png + + + Qt::AlignCenter + + + + + + + Sexist + + + + + + :/images/sexist.png + + + Qt::AlignCenter + + + + + + + + 24 + 24 + + + + Toxic + + + + + + :/images/toxic.png + + + true + + + Qt::AlignCenter + + + + + + + Feeder + + + + + + :/images/feeder.png + + + Qt::AlignCenter + + + + + + + Gives Up + + + + + + :/images/givesup.png + + + Qt::AlignCenter + + + + + + + Destroys Items + + + + + + :/images/destroyer.png + + + Qt::AlignCenter + + + + + + + + + + + + + Racist + + + + + + :/images/racist.png + + + Qt::AlignCenter + + + + + + + Sexist + + + + + + :/images/sexist.png + + + Qt::AlignCenter + + + + + + + + 24 + 24 + + + + Toxic + + + + + + :/images/toxic.png + + + true + + + Qt::AlignCenter + + + + + + + Feeder + + + + + + :/images/feeder.png + + + Qt::AlignCenter + + + + + + + Gives Up + + + + + + :/images/givesup.png + + + Qt::AlignCenter + + + + + + + Destroys Items + + + + + + :/images/destroyer.png + + + Qt::AlignCenter + + + + + + + + + + + + + + 24 + 24 + + + + Racist + + + + + + :/images/racist.png + + + + + + + Sexist + + + + + + :/images/sexist.png + + + + + + + true + + + + 0 + 0 + + + + + 24 + 24 + + + + Toxic + + + + + + :/images/toxic.png + + + true + + + Qt::AlignCenter + + + + + + + Feeder + + + + + + :/images/feeder.png + + + Qt::AlignCenter + + + + + + + Gives Up + + + + + + :/images/givesup.png + + + Qt::AlignCenter + + + + + + + Destroys Items + + + + + + :/images/destroyer.png + + + Qt::AlignCenter + + + + + + + + + + + + + Racist + + + + + + :/images/racist.png + + + Qt::AlignCenter + + + + + + + Sexist + + + + + + :/images/sexist.png + + + Qt::AlignCenter + + + + + + + + 24 + 24 + + + + Toxic + + + + + + :/images/toxic.png + + + true + + + Qt::AlignCenter + + + + + + + Feeder + + + + + + :/images/feeder.png + + + Qt::AlignCenter + + + + + + + Gives Up + + + + + + :/images/givesup.png + + + Qt::AlignCenter + + + + + + + Destroys Items + + + + + + :/images/destroyer.png + + + Qt::AlignCenter + + + + + + + + + + + + + Racist + + + + + + :/images/racist.png + + + Qt::AlignCenter + + + + + + + Sexist + + + + + + :/images/sexist.png + + + Qt::AlignCenter + + + + + + + + 24 + 24 + + + + Toxic + + + + + + :/images/toxic.png + + + true + + + Qt::AlignCenter + + + + + + + Feeder + + + + + + :/images/feeder.png + + + Qt::AlignCenter + + + + + + + Gives Up + + + + + + :/images/givesup.png + + + Qt::AlignCenter + + + + + + + Destroys Items + + + + + + :/images/destroyer.png + + + Qt::AlignCenter + + + + + + + + + + + + + Racist + + + + + + :/images/racist.png + + + Qt::AlignCenter + + + + + + + Sexist + + + + + + :/images/sexist.png + + + Qt::AlignCenter + + + + + + + + 24 + 24 + + + + Toxic + + + + + + :/images/toxic.png + + + true + + + Qt::AlignCenter + + + + + + + Feeder + + + + + + :/images/feeder.png + + + Qt::AlignCenter + + + + + + + Gives Up + + + + + + :/images/givesup.png + + + Qt::AlignCenter + + + + + + + Destroys Items + + + + + + :/images/destroyer.png + + + Qt::AlignCenter + + + + + + + + + + + + + Racist + + + + + + :/images/racist.png + + + Qt::AlignCenter + + + + + + + Sexist + + + + + + :/images/sexist.png + + + Qt::AlignCenter + + + + + + + + 24 + 24 + + + + Toxic + + + + + + :/images/toxic.png + + + true + + + Qt::AlignCenter + + + + + + + Feeder + + + + + + :/images/feeder.png + + + Qt::AlignCenter + + + + + + + Gives Up + + + + + + :/images/givesup.png + + + Qt::AlignCenter + + + + + + + Destroys Items + + + + + + :/images/destroyer.png + + + Qt::AlignCenter + + + + + + + + + + + + + Racist + + + + + + :/images/racist.png + + + Qt::AlignCenter + + + + + + + Sexist + + + + + + :/images/sexist.png + + + Qt::AlignCenter + + + + + + + + 24 + 24 + + + + Toxic + + + + + + :/images/toxic.png + + + true + + + Qt::AlignCenter + + + + + + + Feeder + + + + + + :/images/feeder.png + + + Qt::AlignCenter + + + + + + + Gives Up + + + + + + :/images/givesup.png + + + Qt::AlignCenter + + + + + + + Destroys Items + + + + + + :/images/destroyer.png + + + Qt::AlignCenter + + + + + + + + + + + + + Racist + + + + + + :/images/racist.png + + + Qt::AlignCenter + + + + + + + Sexist + + + + + + :/images/sexist.png + + + Qt::AlignCenter + + + + + + + + 24 + 24 + + + + Toxic + + + + + + :/images/toxic.png + + + true + + + Qt::AlignCenter + + + + + + + Feeder + + + + + + :/images/feeder.png + + + Qt::AlignCenter + + + + + + + Gives Up + + + + + + :/images/givesup.png + + + Qt::AlignCenter + + + + + + + Destroys Items + + + + + + :/images/destroyer.png + + + Qt::AlignCenter + + + + + + + + + + 99999 + + + Qt::AlignCenter + + + + + + + 99999 + + + Qt::AlignCenter + + + + + + + + 0 + 40 + + + + + + + + + + + 99999 + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 100 + 0 + + + + <html><head/><body><p><span style=" font-weight:600;">Smurf</span></p></body></html> + + + Qt::RichText + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + + 0 + 40 + + + + + + + + + + + 99999 + + + Qt::AlignCenter + + + + + + + + 0 + 40 + + + + + + + + + + + + 0 + 40 + + + + + + + + + + + + 0 + 40 + + + + + + + + + + + 99999 + + + Qt::AlignCenter + + + + + + + 99999 + + + Qt::AlignCenter + + + + + + + + 0 + 40 + + + + + + + + + + + 99999 + + + Qt::AlignCenter + + + + + + + + 0 + 40 + + + + + + + + + + + + 0 + 0 + + + + + 50 + 0 + + + + <html><head/><body><p><span style=" font-weight:600;">Games</span></p></body></html> + + + Qt::RichText + + + Qt::AlignCenter + + + + + + + + 0 + 40 + + + + + + + + + + + + 160 + 40 + + + + <html><head/><body><p><span style=" font-weight:600;">Name</span></p></body></html> + + + Qt::RichText + + + Qt::AlignCenter + + + + + + + 99999 + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + 99999 + + + Qt::AlignCenter + + + + + + + 99999 + + + Qt::AlignCenter + + + + + + + + 0 + 40 + + + + + + + + + + + + 0 + 40 + + + + + + + + + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + + + + + + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 140 + 0 + + + + <html><head/><body><p><span style=" font-weight:600;">Flags</span></p></body></html> + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 20 + 40 + + + + + 20 + 40 + + + + background-color: rgb(99, 218, 250) + + + + + + + + + + + 0 + 0 + + + + + 20 + 40 + + + + + 20 + 40 + + + + + + + + + + + + 0 + 0 + + + + + 20 + 40 + + + + + 20 + 40 + + + + background-color: rgb(48, 116, 249) + + + + + + + + + + + 0 + 0 + + + + + 20 + 40 + + + + + 20 + 40 + + + + background-color: rgb(102, 255, 192) + + + + + + + + + + + 0 + 0 + + + + + 20 + 40 + + + + + 20 + 40 + + + + background-color: rgb(189, 0, 183) + + + + + + + + + + + 0 + 0 + + + + + 20 + 40 + + + + + 20 + 40 + + + + background-color: rgb(248, 245, 10) + + + + + + + + + + + 0 + 0 + + + + + 20 + 40 + + + + + 20 + 40 + + + + background-color: rgb(255, 105, 0) + + + + + + + + + + + 0 + 0 + + + + + 20 + 40 + + + + + 20 + 40 + + + + background-color: rgb(254, 136, 197) + + + + + + + + + + + 0 + 0 + + + + + 20 + 40 + + + + + 20 + 40 + + + + background-color: rgb(162, 179, 73) + + + + + + + + + + + 0 + 0 + + + + + 20 + 40 + + + + + 20 + 40 + + + + background-color: rgb(99, 218, 250) + + + + + + + + + + + 0 + 0 + + + + + 20 + 40 + + + + + 20 + 40 + + + + background-color: rgb(1, 131, 31) + + + + + + + + + + + 0 + 0 + + + + + 20 + 40 + + + + + 20 + 40 + + + + background-color: rgb(159, 107, 0) + + + + + + + + + + + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + 120 + 0 + + + + <html><head/><body><p><span style=" font-weight:600;">Custom Name</span></p></body></html> + + + Qt::RichText + + + Qt::AlignCenter + + + + + + + + 120 + 0 + + + + <html><head/><body><p><span style=" font-weight:600;">Pro Name</span></p></body></html> + + + Qt::RichText + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + + + + + + QFrame::Raised + + + 1 + + + 1 + + + Qt::Vertical + + + + + + + + + + + + + + 50 + 16777215 + + + + Qt::LeftToRight + + + Save + + + + + + + + + + + + + Toxic + + + + + + + Racist + + + true + + + false + + + false + + + + + + + Sexist + + + + + + + Feeder + + + + + + + Gives Up + + + + + + + Destroys Items + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Steam ID</span></p></body></html> + + + Qt::RichText + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + <html><head/><body><p><span style=" font-weight:600;">In Game Name</span></p></body></html> + + + Qt::RichText + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Smurf</span></p></body></html> + + + Qt::RichText + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Pro Name</span></p></body></html> + + + Qt::RichText + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Custom Name</span></p></body></html> + + + Qt::RichText + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span></p></body></html> + + + Qt::RichText + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + false + + + + + + 9 + + + + + + + + + + + + + + 0 + 0 + 1282 + 741 + + + + + 0 + 0 + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + <html><head/><body><p><span style=" font-style:italic;">You can request one for free using the </span><a href="https://steamcommunity.com/dev/apikey"><span style=" text-decoration: underline; color:#0000ff;">Steam API Key Form</span></a><span style=" font-style:italic;">. </span></p></body></html> + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Steam Username</span></p></body></html> + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + QLineEdit::Password + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Steam Web API Key</span></p></body></html> + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + <html><head/><body><p><span style=" font-style:italic;">In this mode, the software creates a fake Dota client using the provided Steam username and password (use another account than the one you are playing on) to find the server the searched player is on.<br/>Then, it uses Valve Web API to find the match information.</span></p></body></html> + + + Qt::AlignCenter + + + true + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Save + + + + + + + Cancel + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + QLineEdit::Password + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Mode Client</span></p></body></html> + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + <html><head/><body><p><span style=" font-style:italic;">Use a different Steam Account than the one you are playing on !</span></p></body></html> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Steam Password</span></p></body></html> + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + <html><head/><body><p><span style=" font-style:italic;">Game State Integration (GSI) shows the information of the current game when you spectate it.</span></p><p><span style=" font-style:italic;">To enable it, you need to add </span><a href="aaa"><span style=" text-decoration: underline; color:#0000ff;">this file</span></a><span style=" font-style:italic;"> at:</span></p><p><span style=" font-style:italic;">...\Steam\steamapps\common\dota 2 beta\game\dota\cfg\gamestate_integration\gamestate_integration_notes.cfg</span></p></body></html> + + + + + + + QLineEdit::Password + + + + + + + <html><head/><body><p><span style=" font-style:italic;">Ask for one or setup your own proxy server.</span></p></body></html> + + + + + + + https://dota-notes.the-cluster.org + + + + + + + <html><head/><body><p><span style=" font-style:italic;">Change the server only if you know what you are doing.</span></p></body></html> + + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Mode</span></p></body></html> + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + <html><head/><body><p><span style=" font-weight:600;">API Key</span></p></body></html> + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + <html><head/><body><p><span style=" font-style:italic;">In this mode, the software uses a remote server to do the Dota Client and Steam API requests. Use it if you set up your own server or if you got an API Key.</span></p></body></html> + + + Qt::AlignCenter + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Proxy URL</span></p></body></html> + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Mode Proxy Server</span></p></body></html> + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">General</span></p></body></html> + + + Qt::AlignCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Use GSI to show players when spectating games + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + +