forked from CastroFidel/PortWINE
		
	drop plugin folder from data
This commit is contained in:
		| @@ -1,484 +0,0 @@ | ||||
| #!/usr/bin/env python3 | ||||
|  | ||||
| import os | ||||
| import re | ||||
| import shlex | ||||
| import shutil | ||||
| import logging | ||||
| from configparser import RawConfigParser | ||||
| from pathlib import Path | ||||
| from subprocess import run | ||||
| from types import SimpleNamespace | ||||
| try: | ||||
|     from PyQt6.QtCore import * # type: ignore | ||||
|     from PyQt6.QtGui import * # type: ignore | ||||
|     from PyQt6.QtWidgets import * # type: ignore | ||||
| except ModuleNotFoundError: | ||||
|     from PyQt5.QtCore import * # type: ignore | ||||
|     from PyQt5.QtGui import * # type: ignore | ||||
|     from PyQt5.QtWidgets import * # type: ignore | ||||
|  | ||||
| settings = QSettings('PPGL', 'PortProtonGamesLib') | ||||
| g = SimpleNamespace(locale = '') | ||||
|  | ||||
| class MainWindow(QMainWindow): | ||||
|     def __init__(self): | ||||
|         super().__init__() | ||||
|  | ||||
|         self.resize(QSize(800, 600)) | ||||
|         geometry = settings.value('geometry_main') | ||||
|         if geometry: | ||||
|             self.restoreGeometry(geometry) | ||||
|  | ||||
|         shortcut = RawConfigParser() | ||||
|         shortcut.read(os.getenv('HOME') + '/.local/share/applications/PortProton.desktop') | ||||
|         scripts_dir = shortcut.get('Desktop Entry', 'Path', fallback=os.getenv('HOME') + '/.local/share/PortWINE/PortProton/data/scripts') | ||||
|         if not scripts_dir or not Path(scripts_dir).is_dir(): | ||||
|             QMessageBox.critical(self, 'Error', 'Can not find installed PortProton') | ||||
|             exit(1) | ||||
|         g.scripts_dir = scripts_dir.rstrip('/') | ||||
|         g.pp_icon = shortcut.get('Desktop Entry', 'Icon', fallback='/usr/share/pixmaps/portproton.png') | ||||
|         pp_icon = QIcon(g.pp_icon) | ||||
|         self.setWindowIcon(pp_icon) | ||||
|         self.setWindowTitle('PortProton games library') | ||||
|  | ||||
|         g.base_dir = str(Path(scripts_dir + '/../..').resolve()) | ||||
|         g.install_pfx = g.base_dir + '/data/prefixes/INSTALL' | ||||
|         g.shortcuts_dir = g.base_dir + '/shortcuts' | ||||
|         g.games_dir = g.base_dir + '/games' | ||||
|  | ||||
|         loc_path = Path(g.base_dir + '/data/tmp/PortProton_loc') | ||||
|         if loc_path.exists(): | ||||
|             g.locale = loc_path.read_text().strip() | ||||
|  | ||||
|         Path(g.shortcuts_dir).mkdir(parents=True, exist_ok=True) | ||||
|         Path(g.games_dir).mkdir(parents=True, exist_ok=True) | ||||
|  | ||||
|         sep = QFrame(self) | ||||
|         sep.setFrameShape(QFrame.Shape.VLine) | ||||
|         sep.setFrameShadow(QFrame.Shadow.Sunken) | ||||
|         self._status_size = QLabel(self) | ||||
|         self._status_dir = QLabel(self) | ||||
|         self._status_wine = QLabel(self) | ||||
|         self.statusBar().setVisible(False) | ||||
|         self.statusBar().addWidget(self._status_dir, 1) | ||||
|         self.statusBar().addWidget(self._status_wine) | ||||
|         self.statusBar().addWidget(sep) | ||||
|         self.statusBar().addWidget(self._status_size) | ||||
|  | ||||
|  | ||||
|         self.game_list = GameList(self) | ||||
|         self.setCentralWidget(self.game_list) | ||||
|  | ||||
|         self.toolbar = self.addToolBar('Main') | ||||
|         self.toolbar.setIconSize(QSize(32, 32)) | ||||
|         self.toolbar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon) | ||||
|         self.toolbar.setMovable(False) | ||||
|         action = QAction(self.style().standardIcon(QStyle.StandardPixmap.SP_FileDialogNewFolder), _tr('Install new game'), self) | ||||
|         action.triggered.connect(self.install_game) | ||||
|         self.toolbar.addAction(action) | ||||
|         action = QAction(self.style().standardIcon(QStyle.StandardPixmap.SP_FileLinkIcon), _tr('Add game entry'), self) | ||||
|         action.triggered.connect(self.add_game) | ||||
|         self.toolbar.addAction(action) | ||||
|         action = QAction(self.style().standardIcon(QStyle.StandardPixmap.SP_BrowserReload), _tr('Reload list'), self) | ||||
|         action.triggered.connect(self.reload_list) | ||||
|         self.toolbar.addAction(action) | ||||
|         action = QAction(self.style().standardIcon(QStyle.StandardPixmap.SP_TrashIcon), _tr('Drop install prefix'), self) | ||||
|         action.triggered.connect(self.drop_prefix) | ||||
|         self.toolbar.addAction(action) | ||||
|         spacer = QWidget(self) | ||||
|         spacer.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred) | ||||
|         self.toolbar.addWidget(spacer) | ||||
|         action = QAction(pp_icon, 'PortProton', self) | ||||
|         action.triggered.connect(self.run_pp) | ||||
|         self.toolbar.addAction(action) | ||||
|  | ||||
|     def install_game(self): | ||||
|         InstallGame(self) | ||||
|  | ||||
|     def add_game(self): | ||||
|         InstallGame(self, False) | ||||
|  | ||||
|     def reload_list(self): | ||||
|         self.game_list.reload() | ||||
|  | ||||
|     def drop_prefix(self): | ||||
|         res = QMessageBox.question(self, _tr('Are you sure ?'), _tr('Do you really want to remove<br/><b>{0}</b> ?', g.install_pfx)) | ||||
|         if res == QMessageBox.StandardButton.Yes: | ||||
|             shutil.rmtree(g.install_pfx, True) | ||||
|  | ||||
|     def run_pp(self): | ||||
|         self.setDisabled(True) | ||||
|         app.processEvents() | ||||
|         run([g.scripts_dir + '/start.sh']) | ||||
|         self.setDisabled(False) | ||||
|  | ||||
|     def set_status(self, item): | ||||
|         self.statusBar().setVisible(bool(item)) | ||||
|         if item: | ||||
|             self._status_size.setText('Size: ' + item.dir_size_human) | ||||
|             self._status_dir.setText(' ' + item.game_dir) | ||||
|             self._status_wine.setText(item.wine_use) | ||||
|  | ||||
|     def closeEvent(self, event): | ||||
|         geometry = self.saveGeometry() | ||||
|         settings.setValue('geometry_main', geometry) | ||||
|         super().closeEvent(event) | ||||
|  | ||||
| class LoadListThread(QThread): | ||||
|     completed = pyqtSignal(list) | ||||
|     def __init__(self, parent, install_dir): | ||||
|         super().__init__(parent) | ||||
|         self.install_dir = install_dir | ||||
|     def run(self): | ||||
|         exe_list = list(Path(self.install_dir).glob('**/*.exe')) | ||||
|         self.completed.emit(exe_list) | ||||
|  | ||||
| class InstallGame(QDialog): | ||||
|     def __init__(self, parent, installing=True): | ||||
|         super().__init__(parent) | ||||
|         self._installing = installing | ||||
|         self.install_dir = g.install_pfx + '/drive_c/Games' if installing else g.games_dir | ||||
|         self._exe_list_widget = QListWidget(self) | ||||
|         self._exe_list_widget.setIconSize(QSize(16, 16)) | ||||
|         self._exe_list_widget.itemDoubleClicked.connect(self._handleDoubleClick) | ||||
|         layout = QVBoxLayout() | ||||
|         layout.addWidget(self._exe_list_widget) | ||||
|  | ||||
|         self._pbar = QProgressBar(self) | ||||
|         self._pbar.setMaximum(0) | ||||
|         layout.addWidget(self._pbar) | ||||
|         thread = LoadListThread(self, self.install_dir) | ||||
|         thread.completed.connect(self.load) | ||||
|         thread.start() | ||||
|  | ||||
|         if self._installing: | ||||
|             setup_btn = QPushButton(self) | ||||
|             setup_btn.setIcon(self.style().standardIcon(QStyle.StandardPixmap.SP_FileDialogStart)) | ||||
|             setup_btn.setText(_tr('Run another setup')) | ||||
|             setup_btn.clicked.connect(self._runSetup) | ||||
|             layout.addWidget(setup_btn) | ||||
|         self.setLayout(layout) | ||||
|         self.resize(400, 300) | ||||
|         self.setModal(True) | ||||
|         self.setWindowTitle(_tr('Select game exe file')) | ||||
|         geometry = settings.value('geometry_install') | ||||
|         if geometry: | ||||
|             self.restoreGeometry(geometry) | ||||
|         self.show() | ||||
|  | ||||
|     def load(self, exe_list): | ||||
|         if self._installing and len(exe_list) == 0: | ||||
|             self._runSetup() | ||||
|             exe_list = list(Path(self.install_dir).glob('**/*.exe')) | ||||
|         if len(exe_list) == 0: | ||||
|             return self.close() | ||||
|         def render_list(): | ||||
|             pixmap = QPixmap(16, 16) | ||||
|             pixmap.fill(Qt.GlobalColor.transparent) | ||||
|             empty_icon = QIcon(pixmap) | ||||
|             for exe in sorted(exe_list): | ||||
|                 ico_file = str(exe) + '.ico' | ||||
|                 item = QListWidgetItem(self._exe_list_widget) | ||||
|                 item.setText(str(exe)[len(self.install_dir)+1:]) | ||||
|                 try: | ||||
|                     if not Path(ico_file).exists(): | ||||
|                         run(['wrestool', '-x', '-t14', '-o', ico_file, exe], capture_output=True) | ||||
|                     item.setIcon(QIcon(ico_file)) | ||||
|                 except Exception: | ||||
|                     pass | ||||
|                 if item.icon().pixmap(16, 16).isNull(): | ||||
|                     item.setIcon(empty_icon) | ||||
|                 self._exe_list_widget.addItem(item) | ||||
|             self._pbar.setVisible(False) | ||||
|         thread = QThread(self) | ||||
|         thread.run = render_list | ||||
|         thread.start() | ||||
|  | ||||
|     def _runSetup(self): | ||||
|         downloads_dir = QStandardPaths.writableLocation(QStandardPaths.StandardLocation.DownloadLocation) | ||||
|         exe_file, _ = QFileDialog.getOpenFileName(self, caption=_tr('Choose setup file'), filter='Exe files (*.exe)', directory=downloads_dir) | ||||
|         if not exe_file: | ||||
|             return | ||||
|         ppdb = shlex.quote(exe_file + '.ppdb') | ||||
|         script = f""" | ||||
|             mkdir -p {shlex.quote(g.install_pfx + '/drive_c/Games')} | ||||
|             echo ' | ||||
|                 export PW_VULKAN_USE=1 | ||||
|                 export PW_GUI_DISABLED_CS=1 | ||||
|                 export PW_PREFIX_NAME=INSTALL | ||||
|                 export PW_DLL_INSTALL=mfc42 | ||||
|             ' > {ppdb} | ||||
|             {shlex.quote(g.scripts_dir + '/start.sh')} {shlex.quote(exe_file)} | ||||
|             rm -f {ppdb} | ||||
|         """ | ||||
|         self.setDisabled(True) | ||||
|         app.processEvents() | ||||
|         run(['bash', '-c', script]) | ||||
|         self.setDisabled(False) | ||||
|  | ||||
|     def _handleDoubleClick(self, item): | ||||
|         game_dir = item.text().split('/')[0] | ||||
|         dlg = QInputDialog(self) | ||||
|         dlg.setWindowTitle(_tr('Please enter game entry name')) | ||||
|         dlg.setLabelText(_tr('New game entry')) | ||||
|         dlg.setTextValue(game_dir) | ||||
|         dlg.resize(300, 0) | ||||
|         ok = dlg.exec() | ||||
|         shortcut_name = dlg.textValue() | ||||
|         if not ok or not shortcut_name: | ||||
|             return | ||||
|         file_name = re.sub(r'[<>:/\\|?*]', '_', shortcut_name) | ||||
|         shortcut = f"{g.shortcuts_dir}/{file_name}.desktop" | ||||
|         if Path(shortcut).exists(): | ||||
|             res = QMessageBox.question(self, _tr('Shortcut already exists'), _tr('Shortcut <b>{0}</b> already exists. Overwrite ?', file_name)) | ||||
|             if res != QMessageBox.StandardButton.Yes: | ||||
|                 return | ||||
|         src_dir = self.install_dir + '/' + game_dir | ||||
|         dst_dir = g.games_dir + '/' + game_dir | ||||
|         exe_file = shlex.quote(g.games_dir + '/' + item.text()) | ||||
|         ppdb = shlex.quote(g.games_dir + '/' + item.text() + '.ppdb') | ||||
|         self.setDisabled(True) | ||||
|         if self._installing and Path(dst_dir).exists(): | ||||
|             res = QMessageBox.question(self, _tr('Dir already exists'), _tr('Dir <b>{0}</b> already exists. Overwrite ?', game_dir)) | ||||
|             if res != QMessageBox.StandardButton.Yes: | ||||
|                 return | ||||
|         if self._installing: | ||||
|             os.rename(src_dir, dst_dir) | ||||
|         script = f""" | ||||
|             export INSTALLING_PORT=1 | ||||
|             export portwine_exe={exe_file} | ||||
|             cd {shlex.quote(g.scripts_dir)} | ||||
|             . {shlex.quote(g.scripts_dir + '/runlib')} | ||||
|             pw_init_db | ||||
|             [ -f {ppdb} ] && . {ppdb} | ||||
|             echo -e "export PW_VULKAN_USE=${{PW_VULKAN_USE:-1}}\nexport PW_GUI_DISABLED_CS=1" >> {ppdb} | ||||
|         """ | ||||
|         run(['bash', '-c', script]) | ||||
|         icon_path = g.games_dir + '/' + item.text() + '.ico' | ||||
|         if not Path(icon_path).exists(): | ||||
|             icon_path = g.pp_icon | ||||
|         Path(shortcut).write_text(f"""[Desktop Entry] | ||||
| Name={shortcut_name} | ||||
| Exec=env {shlex.quote(g.scripts_dir + '/start.sh')} {exe_file} | ||||
| Type=Application | ||||
| Categories=Game | ||||
| StartupNotify=true | ||||
| Path={shlex.quote(g.scripts_dir)} | ||||
| Icon={icon_path} | ||||
| """, encoding='utf-8') | ||||
|         os.chmod(shortcut, 0o755) | ||||
|         win.reload_list() | ||||
|         self.close() | ||||
|  | ||||
|     def closeEvent(self, event): | ||||
|         geometry = self.saveGeometry() | ||||
|         settings.setValue('geometry_install', geometry) | ||||
|         super().closeEvent(event) | ||||
|  | ||||
|  | ||||
| class GameList(QListWidget): | ||||
|     def __init__(self, parent): | ||||
|         super().__init__(parent) | ||||
|         self.itemActivated.connect(self.runGame) | ||||
|         self.currentItemChanged.connect(self.selectItem) | ||||
|         self.setViewMode(QListWidget.ViewMode.IconMode) | ||||
|         self.setResizeMode(QListWidget.ResizeMode.Adjust) | ||||
|         self.setIconSize(QSize(64, 64)) | ||||
|         self.setWordWrap(True) | ||||
|         self.setSpacing(3) | ||||
|         self.reload() | ||||
|  | ||||
|     def reload(self): | ||||
|         self.clear() | ||||
|         shortcuts = list(Path(g.shortcuts_dir).glob('*.desktop')) | ||||
|         shortcuts += list(Path(g.base_dir).glob('*.desktop')) | ||||
|         for shortcut in shortcuts: | ||||
|             try: | ||||
|                 item = GameItem(self, shortcut) | ||||
|                 self.addItem(item) | ||||
|             except ValueError: | ||||
|                 pass | ||||
|             except: | ||||
|                 logging.exception('Error while parse "%s"', shortcut) | ||||
|         self.sortItems() | ||||
|         self.setCurrentIndex(QModelIndex()) | ||||
|  | ||||
|     def runGame(self, item): | ||||
|         win.setDisabled(True) | ||||
|         app.processEvents() | ||||
|         run(['bash', '-c', item.get('Exec')]) | ||||
|         win.setDisabled(False) | ||||
|  | ||||
|     def selectItem(self, item): | ||||
|         win.set_status(item) | ||||
|  | ||||
|     def contextMenuEvent(self, event): | ||||
|         selected = self.selectedItems() | ||||
|         if len(selected) == 0: | ||||
|             return | ||||
|         selected = selected[0] | ||||
|         menu = QMenu(self) | ||||
|         desktop = menu.addAction(self.style().standardIcon(QStyle.StandardPixmap.SP_DesktopIcon), _tr('Add to desktop')) | ||||
|         restore_gui = menu.addAction(self.style().standardIcon(QStyle.StandardPixmap.SP_DialogResetButton), _tr('Restore PortProton GUI')) | ||||
|         default_wine = menu.addAction(self.style().standardIcon(QStyle.StandardPixmap.SP_DialogOkButton), _tr('Set default wine')) | ||||
|         remove = menu.addAction(self.style().standardIcon(QStyle.StandardPixmap.SP_TrashIcon), _tr('Remove game entry')) | ||||
|         uninstall = menu.addAction(self.style().standardIcon(QStyle.StandardPixmap.SP_DialogCloseButton), _tr('Uninstall game')) | ||||
|         if not selected.pp_gui_disabled: | ||||
|             restore_gui.setVisible(False) | ||||
|         if not selected.wine_use: | ||||
|             default_wine.setVisible(False) | ||||
|         if not selected.game_dir.startswith(g.games_dir): | ||||
|             uninstall.setVisible(False) | ||||
|         action = menu.exec(self.mapToGlobal(event.pos())) | ||||
|         desktop_shortcut = QStandardPaths.writableLocation(QStandardPaths.StandardLocation.DesktopLocation) + '/' + Path(selected.desktop_file).name | ||||
|         if action == desktop: | ||||
|             if Path(desktop_shortcut).exists(): | ||||
|                 res = QMessageBox.question(self, _tr('Shortcut already exists'), _tr('Shortcut <b>{0}</b> already exists. Overwrite ?', desktop_shortcut)) | ||||
|                 if res != QMessageBox.StandardButton.Yes: | ||||
|                     return | ||||
|             shutil.copy(selected.desktop_file, desktop_shortcut) | ||||
|         if action == restore_gui or action == default_wine: | ||||
|             ignore_line = 'PW_GUI_DISABLED_CS' if action == restore_gui else 'PW_WINE_USE' | ||||
|             ppdb = shlex.split(selected.get('Exec'))[-1] + '.ppdb' | ||||
|             if not Path(ppdb).exists(): | ||||
|                 return | ||||
|             with open(ppdb, 'r') as read: | ||||
|                 with open(ppdb + '.new', 'w') as write: | ||||
|                     while (line := read.readline()): | ||||
|                         if ignore_line not in line: | ||||
|                             write.write(line) | ||||
|             os.rename(ppdb + '.new', ppdb) | ||||
|             if action == restore_gui: | ||||
|                 selected.pp_gui_disabled = False | ||||
|             if action == default_wine: | ||||
|                 selected.wine_use = None | ||||
|                 self.selectItem(selected) | ||||
|         def remove_shortcut(): | ||||
|             Path(desktop_shortcut).unlink(True) | ||||
|             Path(selected.desktop_file).unlink(True) | ||||
|             def_icon_path = g.base_dir + '/data/img/' + Path(shlex.split(selected.get('Exec'))[-1]).stem + '.png' | ||||
|             Path(def_icon_path).unlink(True) | ||||
|         if action == remove: | ||||
|             remove_shortcut() | ||||
|             self.reload() | ||||
|         if action == uninstall: | ||||
|             res = QMessageBox.question(self, | ||||
|                 _tr('Are you sure ?'), | ||||
|                 _tr('Do you really want to uninstall <b>{0}</b><br/>located in "<b>{1}</b>" ?', selected.get('Name'), selected.game_dir) | ||||
|             ) | ||||
|             if res != QMessageBox.StandardButton.Yes: | ||||
|                 return | ||||
|             remove_shortcut() | ||||
|             if selected.game_dir.startswith(g.games_dir): | ||||
|                 shutil.rmtree(selected.game_dir, True) | ||||
|             self.reload() | ||||
|  | ||||
|  | ||||
| def human_size(num): | ||||
|     if not num: | ||||
|         return "-" | ||||
|     for unit in ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]: | ||||
|         if abs(num) < 1024.0: | ||||
|             return f"{num:.2f} {unit}B" | ||||
|         num /= 1024.0 | ||||
|     return f"{num:.2f} YiB" | ||||
|  | ||||
| class GameItem(QListWidgetItem): | ||||
|     def __init__(self, parent, desktop_file): | ||||
|         self.desktop_file = desktop_file | ||||
|         self.config = RawConfigParser() | ||||
|         self.config.read(desktop_file) | ||||
|         text = self.get('Name', Path(desktop_file).stem) | ||||
|         if not self.get('Exec') or text == 'PortProton': | ||||
|             raise ValueError('Validation fail') | ||||
|         exe_file = shlex.split(self.get('Exec'))[-1] | ||||
|         if exe_file.startswith(g.games_dir): | ||||
|             self.game_dir = g.games_dir + '/' + exe_file[len(g.games_dir)+1:].split('/')[0] | ||||
|         else: | ||||
|             self.game_dir = str(Path(exe_file).parent) | ||||
|         if self.game_dir == '.': | ||||
|             raise ValueError('Can not determine game dir') | ||||
|         self.pp_gui_disabled = False | ||||
|         self.wine_use = None | ||||
|         ppdb = exe_file + '.ppdb' | ||||
|         if Path(ppdb).exists(): | ||||
|             ppdb_conf = RawConfigParser(strict=False) | ||||
|             with open(ppdb) as f: | ||||
|                 ppdb_conf.read_string('[dummy]\n' + f.read()) | ||||
|             pp_gui_disabled = ppdb_conf.get('dummy', 'export PW_GUI_DISABLED_CS', fallback='').strip('"') | ||||
|             try: self.pp_gui_disabled = bool(int(pp_gui_disabled)) | ||||
|             except: self.pp_gui_disabled = bool(pp_gui_disabled) | ||||
|             self.wine_use = ppdb_conf.get('dummy', 'export PW_WINE_USE', fallback='').strip('"') | ||||
|  | ||||
|         super().__init__(parent) | ||||
|  | ||||
|         self.setToolTip(text) | ||||
|         self.setText(text) | ||||
|         icon_path = self.get('Icon') if Path(self.get('Icon')).exists() else g.pp_icon | ||||
|         qicon = QIcon(icon_path) | ||||
|         self.setIcon(qicon) | ||||
|         self.setTextAlignment(Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignTop) | ||||
|         self.setSizeHint(QSize(100, 105)) | ||||
|  | ||||
|         self._set_dir_size(None) | ||||
|         dir_size_cache = self.game_dir + '/.size' | ||||
|         if Path(dir_size_cache).exists(): | ||||
|             self._set_dir_size(int(Path(dir_size_cache).read_text())) | ||||
|         else: | ||||
|             def calc_dir_size(): | ||||
|                 if not Path(self.game_dir).exists(): | ||||
|                     return | ||||
|                 dir_size = sum(p.stat(follow_symlinks=False).st_size for p in Path(self.game_dir).rglob('*')) | ||||
|                 self._set_dir_size(dir_size) | ||||
|                 Path(dir_size_cache).write_text(str(dir_size)) | ||||
|             thread = QThread(parent) | ||||
|             thread.run = calc_dir_size | ||||
|             thread.start() | ||||
|  | ||||
|     def get(self, name, fallback=None): | ||||
|         return self.config.get('Desktop Entry', name, fallback=fallback) | ||||
|  | ||||
|     def _set_dir_size(self, size): | ||||
|         self.dir_size = size | ||||
|         self.dir_size_human = human_size(size) | ||||
|  | ||||
| import signal | ||||
| signal.signal(signal.SIGINT, signal.SIG_DFL) | ||||
|  | ||||
| lang = { | ||||
|     'RUS': { | ||||
|         'Install new game': 'Установить игру', | ||||
|         'Add game entry': 'Добавить в список', | ||||
|         'Reload list': 'Обновить список', | ||||
|         'Drop install prefix': 'Удалить установочный префикс', | ||||
|         'Are you sure ?': 'Вы уверены ?', | ||||
|         'Do you really want to remove<br/><b>{0}</b> ?': 'Вы действительно хотите удалить<br/><b>{0}</b> ?', | ||||
|         'Run another setup': 'Запустить установку', | ||||
|         'Select game exe file': 'Выберите exe файл игры', | ||||
|         'Choose setup file': 'Выберите установочный файл', | ||||
|         'Please enter game entry name': 'Введите название игры', | ||||
|         'New game entry': 'Название игры', | ||||
|         'Shortcut already exists': 'Ярлык уже существует', | ||||
|         'Shortcut <b>{0}</b> already exists. Overwrite ?': 'Ярлык <b>{0}</b> уже существует. Перезаписать ?', | ||||
|         'Dir already exists': 'Директория уже существует', | ||||
|         'Dir <b>{0}</b> already exists. Overwrite ?': 'Директория <b>{0}</b> уже существует. Перезаписать ?', | ||||
|         'Add to desktop': 'Добавить на рабочий стол', | ||||
|         'Restore PortProton GUI': 'Восстановить PortProton GUI', | ||||
|         'Set default wine': 'Выбрать дефолтный wine', | ||||
|         'Remove game entry': 'Убрать из списка', | ||||
|         'Uninstall game': 'Удалить игру', | ||||
|         'Do you really want to uninstall <b>{0}</b><br/>located in "<b>{1}</b>" ?': 'Вы действительно хотите удалить <b>{0}</b><br/>расположеную в "<b>{1}</b>" ?' | ||||
|     } | ||||
| } | ||||
| def _tr(text, *fmt): | ||||
|     res = lang.get(g.locale, {}).get(text, text) | ||||
|     if fmt: | ||||
|         res = res.format(*fmt) | ||||
|     return res | ||||
|  | ||||
| app = QApplication([]) | ||||
| app.setDesktopFileName('PortProton') | ||||
| win = MainWindow() | ||||
| win.show() | ||||
| app.exec() | ||||
		Reference in New Issue
	
	Block a user