import os from PyQt6.QtWidgets import QApplication, QLabel, QPushButton, QButtonGroup from PyQt6.QtGui import QPixmap, QIcon, QPainter, QColor, QFont, QTransform from PyQt6.QtCore import Qt from PyQt6 import QtCore from gui.v2.ui.pages.Page import Page class LocationPage(Page): def __init__(self, page_stack, main_window, parent=None): super().__init__("Location", page_stack, main_window, parent) self.selected_location_icon = None self.update_status = main_window self.button_reverse.setVisible(True) self.connection_manager = main_window.connection_manager self.button_reverse.clicked.connect(self.reverse) self.display.setGeometry(QtCore.QRect(5, 10, 390, 520)) self.title.setGeometry(395, 40, 380, 40) self.title.setText("Pick a location") self.initial_display = QLabel(self) self.initial_display.setGeometry(5, 22, 355, 485) self.initial_display.setAlignment(Qt.AlignmentFlag.AlignCenter) self.initial_display.setWordWrap(True) self.verification_button = QPushButton("More Info", self) self.verification_button.setGeometry(10, 70, 160, 40) self.verification_button.setStyleSheet(f""" QPushButton {{ background-color: rgba(60, 80, 120, 1.0); border: 2px solid rgba(100, 140, 200, 1.0); border-radius: 5px; color: rgb(255, 255, 255); font-size: 15px; font-weight: bold; padding: 5px 10px; }} QPushButton:hover {{ background-color: rgba(80, 100, 140, 1.0); border: 2px solid rgba(120, 160, 220, 1.0); }} QPushButton:disabled {{ background-color: rgba(40, 50, 70, 0.6); border: 2px solid rgba(70, 90, 110, 0.6); opacity: 0.5; }} """) self.verification_button.setCursor( QtCore.Qt.CursorShape.PointingHandCursor) self.verification_button.setEnabled(False) self.verification_button.show() if self.connection_manager.is_synced(): from gui.v2.actions.sync import generate_grid_positions locs = self.connection_manager.get_location_list() positions = generate_grid_positions(len(locs)) available = [(QPushButton, loc, positions[i]) for i, loc in enumerate(locs)] self.create_interface_elements(available) def showEvent(self, event): super().showEvent(event) self.button_next.setVisible(False) for button in self.buttons: button.setChecked(False) if hasattr(self, 'verification_button'): self.verification_button.setEnabled(False) def create_interface_elements(self, available_locations): self.buttonGroup = QButtonGroup(self) self.buttons = [] for j, (object_type, icon_name, geometry) in enumerate(available_locations): boton = object_type(self) boton.setGeometry(*geometry) boton.setIconSize(boton.size()) boton.setCheckable(True) locations = self.connection_manager.get_location_info(icon_name) if locations and not (hasattr(locations, 'is_wireguard_capable') and locations.is_wireguard_capable): boton.setVisible(False) icon_path = os.path.join(self.btn_path, f"button_{icon_name}.png") boton.setIcon(QIcon(icon_path)) fallback_path = os.path.join( self.btn_path, "default_location_button.png") if locations: try: provider = locations.operator.name if locations and hasattr( locations, 'operator') else None except: print("Assign none") provider = None if boton.icon().isNull(): if locations and hasattr(locations, 'country_name'): location_name = locations.country_name base_image = LocationPage.create_location_button_image( location_name, fallback_path, provider) boton.setIcon(QIcon(base_image)) else: base_image = LocationPage.create_location_button_image( '', fallback_path, provider) boton.setIcon(QIcon(base_image)) else: if locations and hasattr(locations, 'country_name'): base_image = LocationPage.create_location_button_image( f'{locations.country_code}_{locations.code}', fallback_path, provider, icon_path) boton.setIcon(QIcon(base_image)) else: base_image = LocationPage.create_location_button_image( '', fallback_path, provider, icon_path) boton.setIcon(QIcon(base_image)) self.buttons.append(boton) self.buttonGroup.addButton(boton, j) boton.location_icon_name = icon_name boton.setCursor(QtCore.Qt.CursorShape.PointingHandCursor) boton.clicked.connect( lambda checked, loc=icon_name: self.show_location(loc)) def update_swarp_json(self, get_connection=False): profile_data = self.update_status.read_data() self.connection_type = profile_data.get("connection", "") if get_connection: return self.connection_type inserted_data = { "location": self.selected_location_icon } self.update_status.write_data(inserted_data) def show_location(self, location): self.initial_display.hide() max_size = QtCore.QSize(300, 300) target_size = self.display.size().boundedTo(max_size) self.display.setPixmap(QPixmap(os.path.join(self.btn_path, f"icon_{location}.png")).scaled( target_size, Qt.AspectRatioMode.KeepAspectRatio)) self.selected_location_icon = location self.button_next.setVisible(True) self.button_next.clicked.connect(self.go_selected) self.update_swarp_json() try: self.verification_button.clicked.disconnect() except TypeError: pass self.verification_button.clicked.connect( lambda: self.show_location_verification(location)) self.verification_button.setEnabled(True) def reverse(self): self.custom_window.navigator.navigate("protocol") def go_selected(self): if self.connection_type == "system-wide": self.custom_window.navigator.navigate("resume") else: self.custom_window.navigator.navigate("browser") def show_location_verification(self, location_icon_name): from gui.v2.ui.pages.location_verification_page import LocationVerificationPage verification_page = LocationVerificationPage( self.page_stack, self.update_status, location_icon_name, self) self.page_stack.addWidget(verification_page) self.page_stack.setCurrentIndex( self.page_stack.indexOf(verification_page)) @staticmethod def create_location_button_image(location_name, fallback_image_path, provider=None, existing_icon_path=None): if existing_icon_path: base_image = QPixmap(existing_icon_path) if base_image.isNull(): base_image = QPixmap(fallback_image_path) draw_location_text = False else: base_image = QPixmap(fallback_image_path) draw_location_text = True if base_image.isNull(): return base_image painter = QPainter(base_image) try: if draw_location_text: font_size = 12 app_font = QApplication.font() app_font.setPointSize(font_size) app_font.setWeight(QFont.Weight.Bold) text_length = len(location_name) if text_length <= 10: font_stretch = 100 text_width_scale = 1.1 text_height_scale = 1.4 elif text_length <= 15: font_stretch = 90 text_width_scale = 1.0 text_height_scale = 2 else: font_stretch = 100 text_width_scale = 1.1 text_height_scale = 4.5 app_font.setStretch(font_stretch) painter.setFont(app_font) painter.setPen(QColor(0, 255, 255)) text_rect = painter.fontMetrics().boundingRect(location_name) max_width = 110 while text_rect.width() > max_width: font_size -= 1 app_font.setPointSize(font_size) app_font.setWeight(QFont.Weight.Bold) painter.setFont(app_font) text_rect = painter.fontMetrics().boundingRect(location_name) x = ((base_image.width() - text_rect.width()) // 2) - 30 y = ((base_image.height() + text_rect.height()) // 2) - 15 transform = QTransform() transform.scale(text_width_scale, text_height_scale) painter.setTransform(transform) x_scaled = int(x / text_width_scale) y_scaled = int(y / text_height_scale) shadow_offset = 1 painter.setPen(QColor(0, 0, 0)) painter.drawText(x_scaled + shadow_offset, y_scaled + shadow_offset, location_name) painter.setPen(QColor(0, 255, 255)) painter.drawText(x_scaled, y_scaled, location_name) painter.setTransform(QTransform()) if provider: painter.setPen(QColor(128, 128, 128)) provider_text_font = QApplication.font() provider_text_font.setPointSize(7) provider_text_font.setWeight(QFont.Weight.Normal) painter.setFont(provider_text_font) provider_text_rect = painter.fontMetrics().boundingRect(provider) provider_x = ( (base_image.width() - provider_text_rect.width()) // 2) - 30 provider_y = 50 px = int(provider_x) py = int(provider_y) painter.setFont(provider_text_font) painter.drawText(px + 5, py + 2, provider) finally: painter.end() return base_image