7 Commits

Author SHA1 Message Date
GenevensiS d9b58bb5eb Selection highlight debug for linux
this is not optimized but it'll do for now
2026-06-05 05:08:57 +02:00
GenevensiS 512a237f39 fix keywords panel 2026-06-05 02:45:56 +02:00
GenevensiS 1a64496206 fix bug not loading links correctly 2026-05-27 20:30:38 +02:00
GenevensiS 23463c4b96 don't print scientific notation in to_json 2026-05-24 16:14:13 +02:00
GenevensiS 6f526a81f1 fix link window appearing on wrong monitor 2026-05-24 13:25:26 +02:00
GenevensiS ae02c71be6 console and to_json function now accept stylesheets, games and style index maps 2026-05-20 15:50:54 +02:00
GenevensiS c531b8aa74 Add option to download missing stylesheets on startup 2026-05-18 23:31:39 +02:00
63 changed files with 870 additions and 216 deletions
+3 -4
View File
@@ -27,10 +27,9 @@ if( NOT HUNSPELL_FOUND )
endif()
endif()
# You will most likely get a message about being unable to open hunspell-1.7.lib because pkgconf forgets to add the actual path to
# HUNSPELL_LIBRARIES. If so, uncomment the below line and point it to the correct vcpkg root folder/library.
# You will most likely get a message about being unable to open hunspell-1.7.lib because pkgconf forgets to add the actual path to HUNSPELL_LIBRARIES.
# If so, uncomment the below line and point it to the correct vcpkg root folder/library. (For debug builds, add "debug\\" just before "lib\\")
#set(HUNSPELL_LIBRARIES "C:\\PATH\\TO\\ROOT\\vcpkg\\installed\\${VCPKG_TARGET_TRIPLET}\\lib\\hunspell-1.7.lib")
message("-- Does this have a full path? If not, and it's just a file name, it's broken: Found Hunspell at ${HUNSPELL_LIBRARIES}")
include_directories("${PROJECT_BINARY_DIR}/src")
include_directories("${PROJECT_SOURCE_DIR}/src")
@@ -143,4 +142,4 @@ endif()
include(test/tests.cmake)
# Debug Message
message("-- Does this have a full path? If not, and it's just a file name, it's broken: Found Hunspell at ${HUNSPELL_LIBRARIES}")
message("-- Does this have a full path? If not, and it's just a file name, it's broken: ${HUNSPELL_LIBRARIES}")
+18
View File
@@ -18,6 +18,24 @@
}
]
},
{
"name": "x64-Debug-static",
"generator": "Ninja",
"configurationType": "Debug",
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "-DVCPKG_TARGET_TRIPLET=x64-windows-static",
"buildCommandArgs": "-v",
"ctestCommandArgs": "",
"inheritEnvironments": [ "msvc_x64_x64" ],
"variables": [
{
"name": "VCPKG_MANIFEST_FEATURES",
"value": "fonts",
"type": "STRING"
}
]
},
{
"name": "x86-Debug",
"generator": "Ninja",
+21 -1
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8
mse version: 2.6.0
installer group: Magic Set Editor/translations/chinese simplified
full name: 简体中文 (Simplified Chinese)
version: 2026-02-28
@@ -620,6 +620,16 @@ label:
stylesheet not found:
你要打开的套牌使用的是 "%s" 样式表
这个样式表在你的系统里没有找到,请选择其他方案
#TODO: Localize
searching online: Searching online...
#TODO: Localize
searching online fail: Not found online
#TODO: Localize
found online downloading: Found online! Downloading...
#TODO: Localize
found online installing: Found online! Installing...
#TODO: Localize
found online fail: Installation failed
# preferences dialog
language: 语言
@@ -904,6 +914,10 @@ button:
upgrade group: 全部升级
remove group: 全部移除
# stylesheet not found dialog
#TODO: Localize
find package online: Search Online
############################################################## Titles in the GUI
title:
# window titles
@@ -1064,6 +1078,12 @@ error:
file not found package like:
没有找到文件:'%s' 在 '%s' 文件包中
如果你尝试从别的文件包中打开文件, 使用以下格式"/package/filename"
#TODO: Localize
file not found package like init:
File not found: '%s' in package '%s'
If this folder is empty or unused, delete it.
#TODO: Localize
package name parse error: Unable to parse package name '%s'
file parse error:
处理文件发生错误:'%s'
%s
+21 -1
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8
mse version: 2.6.0
installer group: Magic Set Editor/translations/chinese traditional
full name: 繁體中文 (Traditional Chinese)
version: 2026-02-28
@@ -618,6 +618,16 @@ label:
stylesheet not found:
你要打開的套牌使用的是 "%s" 樣式表
這個樣式表在你的系統里沒有找到,請選擇其他方案
#TODO: Localize
searching online: Searching online...
#TODO: Localize
searching online fail: Not found online
#TODO: Localize
found online downloading: Found online! Downloading...
#TODO: Localize
found online installing: Found online! Installing...
#TODO: Localize
found online fail: Installation failed
# preferences dialog
language: 語言
@@ -902,6 +912,10 @@ button:
upgrade group: 全部昇級
remove group: 全部移除
# stylesheet not found dialog
#TODO: Localize
find package online: Search Online
############################################################## Titles in the GUI
title:
# window titles
@@ -1062,6 +1076,12 @@ error:
file not found package like:
沒有找到文件:'%s' 在 '%s' 文件包中
如果你嘗試從別的文件包中打開文件, 使用以下格式"/package/filename"
#TODO: Localize
file not found package like init:
File not found: '%s' in package '%s'
If this folder is empty or unused, delete it.
#TODO: Localize
package name parse error: Unable to parse package name '%s'
file parse error:
處理文件發生錯誤:'%s'
%s
+21 -1
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8
mse version: 2.6.0
installer group: Magic Set Editor/translations/danish
full name: Dansk (Danish)
version: 2026-02-28
@@ -630,6 +630,16 @@ label:
stylesheet not found:
Sættet du har åbner bruger stilen "%s".
Denne stil er ikke i dit system, vælg venligst et alternativ.
#TODO: Localize
searching online: Searching online...
#TODO: Localize
searching online fail: Not found online
#TODO: Localize
found online downloading: Found online! Downloading...
#TODO: Localize
found online installing: Found online! Installing...
#TODO: Localize
found online fail: Installation failed
# preferences dialog
language: Sprog
@@ -920,6 +930,10 @@ button:
upgrade group: &Opgradér Alt
remove group: &Fjern Alt
# stylesheet not found dialog
#TODO: Localize
find package online: Search Online
############################################################## Titles in the GUI
title:
# window titles
@@ -1086,6 +1100,12 @@ error:
file not found package like:
File not found: '%s' in package '%s'
If you are trying to open a file from another package, use "/package/filename"
#TODO: Localize
file not found package like init:
File not found: '%s' in package '%s'
If this folder is empty or unused, delete it.
#TODO: Localize
package name parse error: Unable to parse package name '%s'
file parse error:
Error while parsing file: '%s'
%s
+16 -3
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8
mse version: 2.6.0
installer group: Magic Set Editor/translations/german
full name: Deutsch (German)
version: 2026-02-28
@@ -21,7 +21,7 @@ menu:
export images: Alle Bilder exportieren...
export apprentice: &Karte exportieren...
export mws: Magic &Workstation...
check updates: Nach Updates schauen...
check updates: Aktualisierungen / Neue Stylesheets...
print preview: Druckvorschau...
print: &Drucken... Ctrl+P
reload data: Daten neu laden Ctrl+F5
@@ -581,7 +581,13 @@ label:
# stylesheet not found dialog
stylesheet not found:
Die ausgewählte Edition benutzt das Stylesheet "%s" .
Leider konnte es nicht gefunden werden. Bitte probieren Sie ein anderes.
Dieses Stylesheet wurde auf Ihrem System nicht gefunden.
Bitte wählen Sie eine Alternative oder suchen Sie online danach.
searching online: Online-Suche...
searching online fail: Nicht gefunden
found online downloading: Online gefunden! Wird heruntergeladen...
found online installing: Online gefunden! Wird installiert...
found online fail: Installation fehlgeschlagen
# preferences dialog
language: Sprache
@@ -836,6 +842,9 @@ button:
upgrade group: Gruppe aktualisieren
remove group: Gruppe entfernen
# stylesheet not found dialog
find package online: Online Suchen
############################################################## Titles in the GUI
title:
# window titles
@@ -984,6 +993,10 @@ error:
file not found package like:
Datei nicht gefunden: '%s' im Package '%s'
Wenn Sie versuchen sollten, die Datei von einem anderen Package zu laden, verwenden Sie "/package/filename"
file not found package like init:
Datei nicht gefunden: '%s' im Package '%s'
Wenn dieser Ordner leer oder nicht verwendet ist, löschen Sie ihn.
package name parse error: Packagename '%s' konnte nicht analysiert werden.
file parse error:
Fehler beim Parsen von Datei: '%s'
%s
+16 -3
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8
mse version: 2.6.0
installer group: Magic Set Editor/translations/english
full name: English
version: 2026-02-28
@@ -21,7 +21,7 @@ menu:
export images: All Card I&mages...
export apprentice: &Apprentice...
export mws: Magic &Workstation...
check updates: Check &Updates...
check updates: Check &Updates / New Styles...
print preview: Print Pre&view...
print: &Print... Ctrl+P
reload data: Reload Data Ctrl+F5
@@ -582,7 +582,13 @@ label:
# stylesheet not found dialog
stylesheet not found:
The set you are trying to open uses the stylesheet "%s".
This stylesheet is not found on your system, please select an alternative.
This stylesheet is not found on your system.
Please select an alternative, or look for it online.
searching online: Searching online...
searching online fail: Not found online
found online downloading: Found online! Downloading...
found online installing: Found online! Installing...
found online fail: Installation failed
# preferences dialog
language: Language
@@ -837,6 +843,9 @@ button:
upgrade group: &Update Group
remove group: &Remove Group
# stylesheet not found dialog
find package online: Search Online
############################################################## Titles in the GUI
title:
# window titles
@@ -985,6 +994,10 @@ error:
file not found package like:
File not found: '%s' in package '%s'
If you are trying to open a file from another package, use "/package/filename"
file not found package like init:
File not found: '%s' in package '%s'
If this folder is empty or unused, delete it.
package name parse error: Unable to parse package name '%s'
file parse error:
Error while parsing file: '%s'
%s
+21 -1
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8
mse version: 2.6.0
installer group: Magic Set Editor/translations/spanish
full name: Español (Spanish)
version: 2026-02-28
@@ -621,6 +621,16 @@ label:
stylesheet not found:
El Set que estás intentando abrir usa el estilo "%s".
Este estilo no se encuentra en tu sistema, por favor selecciona otro.
#TODO: Localize
searching online: Searching online...
#TODO: Localize
searching online fail: Not found online
#TODO: Localize
found online downloading: Found online! Downloading...
#TODO: Localize
found online installing: Found online! Installing...
#TODO: Localize
found online fail: Installation failed
# preferences dialog
language: Idioma
@@ -905,6 +915,10 @@ button:
upgrade group: A&ctualizar Todos
remove group: Q&uitar Todos
# stylesheet not found dialog
#TODO: Localize
find package online: Search Online
############################################################## Titles in the GUI
title:
# window titles
@@ -1065,6 +1079,12 @@ error:
file not found package like:
Archivo no encontrado: '%s' en el paquete '%s'
Si estás intentando abrir un archivo de otro paquete, usa "/package/filename"
#TODO: Localize
file not found package like init:
File not found: '%s' in package '%s'
If this folder is empty or unused, delete it.
#TODO: Localize
package name parse error: Unable to parse package name '%s'
file parse error:
Error mientras se analizaba el archivo: '%s'
%s
+16 -3
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8
mse version: 2.6.0
installer group: Magic Set Editor/translations/french
full name: Français (French)
version: 2026-02-28
@@ -21,7 +21,7 @@ menu:
export images: Toutes les I&mages de Carte...
export apprentice: &Apprentice...
export mws: Magic &Workstation...
check updates: Vérifier les Mises à Jo&ur...
check updates: Mises à Jo&ur / Nouveaux Styles...
print preview: Aperçu d'&Impression...
print: &Imprimer... Ctrl+P
reload data: Recharger les Données Ctrl+F5
@@ -582,7 +582,13 @@ label:
# stylesheet not found dialog
stylesheet not found:
Le Set que vous essayez d'ouvrir utilise le Style "%s".
Ce Style n'a pas été trouvé sur votre ordinateur. Selectionnez une alternative.
Ce Style n'a pas été trouvé sur votre ordinateur.
Selectionnez une alternative, ou cherchez en ligne.
searching online: Recherche en ligne...
searching online fail: Introuvable en ligne
found online downloading: Trouvé en ligne! Téléchargement...
found online installing: Trouvé en ligne! Installation...
found online fail: Échec de linstallation
# preferences dialog
language: Langue
@@ -836,6 +842,9 @@ button:
upgrade group: &Mettre à jour le groupe
remove group: &Supprimer le groupe
# stylesheet not found dialog
find package online: Chercher En Ligne
############################################################## Titles in the GUI
title:
# window titles
@@ -984,6 +993,10 @@ error:
file not found package like:
Fichier non trouvé: '%s' dans le package '%s'
Si vous essayez d'ouvrir un fichier d'un autre package, utilisez "/package/fichier"
file not found package like init:
Fichier non trouvé: '%s' dans le package '%s'
Si ce dossier est vide ou inutilisé, supprimez-le.
package name parse error: Impossible d'analyser le nom du package '%s'.
file parse error:
Erreur lors de la lecture du fichier: '%s'
%s
+16 -3
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8
mse version: 2.6.0
installer group: Magic Set Editor/translations/italian
full name: Italiano (Italian)
version: 2026-02-28
@@ -21,7 +21,7 @@ menu:
export images: I&mmagini Carte...
export apprentice: &Apprentice...
export mws: Magic &Workstation...
check updates: Cerca aggiornamenti...
check updates: Aggiornamenti / Nuovi Stili...
print preview: Anteprima di S&tampa...
print: &Stampa... Ctrl+P
reload data: Ricarica dati Ctrl+F5
@@ -582,7 +582,13 @@ label:
# stylesheet not found dialog
stylesheet not found:
Il set che stai cercando di aprire usa lo stile "%s".
Questo stile non è stato trovato sul tuo sistema, scegli un'alternativa.
Questo stile non è stato trovato sul tuo sistema.
Seleziona un'alternativa o cercalo online.
searching online: Ricerca online in corso...
searching online fail: Non trovato online
found online downloading: Trovato online! Download in corso...
found online installing: Trovato online! Installazione in corso...
found online fail: Installazione non riuscita
# preferences dialog
language: Lingua
@@ -836,6 +842,9 @@ button:
upgrade group: &Aggiorna il gruppo
remove group: &Rimuovi il gruppo
# stylesheet not found dialog
find package online: Cerca online
############################################################## Titles in the GUI
title:
# window titles
@@ -984,6 +993,10 @@ error:
file not found package like:
File non trovato: '%s' nel pacchetto '%s'
Se si sta tentando di aprire un file da un altro pacchetto, utilizzare "/package/filename"
file not found package like init:
File non trovato: '%s' nel pacchetto '%s'
Se questa cartella è vuota o inutilizzata, eliminala.
package name parse error: Impossibile analizzare il nome del pacchetto '%s'
file parse error:
Errore analizzando il file: '%s'
%s
+21 -1
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8
mse version: 2.6.0
installer group: Magic Set Editor/translations/japanese
full name: 日本語 (Japanese)
version: 2026-02-28
@@ -620,6 +620,16 @@ label:
stylesheet not found:
あなたが始めようとしているセットがスタイルシートを使う "%s"。
このstylesheetがあなたのシステムで見つからないで、選択肢を選んでください。
#TODO: Localize
searching online: Searching online...
#TODO: Localize
searching online fail: Not found online
#TODO: Localize
found online downloading: Found online! Downloading...
#TODO: Localize
found online installing: Found online! Installing...
#TODO: Localize
found online fail: Installation failed
# preferences dialog
language: 言語
@@ -904,6 +914,10 @@ button:
upgrade group: すべてアップグレードする
remove group: すべて削除する
# stylesheet not found dialog
#TODO: Localize
find package online: Search Online
############################################################## Titles in the GUI
title:
# window titles
@@ -1065,6 +1079,12 @@ error:
file not found package like:
ファイルが見つかりません '%s' パッケージの '%s'
しようとしている場合は、別のパッケージからファイルを開くには、使用する "/パッケージ/ファイル名"
#TODO: Localize
file not found package like init:
File not found: '%s' in package '%s'
If this folder is empty or unused, delete it.
#TODO: Localize
package name parse error: Unable to parse package name '%s'
file parse error:
ファイルをパースし誤り: '%s'
%s
+21 -1
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8
mse version: 2.6.0
installer group: Magic Set Editor/translations/korean
full name: 한국어 (Korean)
version: 2026-02-28
@@ -625,6 +625,16 @@ label:
stylesheet not found:
열려고 하는 세트는 스타일시트 '%s'을 사용합니다.
이 스타일시트를 시스템에서 찾을 수 없습니다. 대체 스타일을 선택하십시오.
#TODO: Localize
searching online: Searching online...
#TODO: Localize
searching online fail: Not found online
#TODO: Localize
found online downloading: Found online! Downloading...
#TODO: Localize
found online installing: Found online! Installing...
#TODO: Localize
found online fail: Installation failed
# preferences dialog
language: 언어
@@ -910,6 +920,10 @@ button:
upgrade group: 모두 업그레이드
remove group: 모두 제거
# stylesheet not found dialog
#TODO: Localize
find package online: Search Online
############################################################## Titles in the GUI
title:
# window titles
@@ -1071,6 +1085,12 @@ error:
file not found package like:
파일을 찾을 수 없습니다: '%s' 패키지에 '%s'
다른 패키지의 파일을 열려고 하는 경우 다음을 사용하십시오. "/패키지 이름/파일 이름"
#TODO: Localize
file not found package like init:
File not found: '%s' in package '%s'
If this folder is empty or unused, delete it.
#TODO: Localize
package name parse error: Unable to parse package name '%s'
file parse error:
파일을 구문 분석하는 중 오류가 발생했습니다.: '%s'
%s
+21 -1
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8
mse version: 2.6.0
installer group: Magic Set Editor/translations/polski
full name: Polski (Polish)
version: 2026-02-28
@@ -660,6 +660,16 @@ label:
stylesheet not found:
Zestaw który próbujesz otworzyć używa stylu z arkusz "%s".
Nie udało się znaleźć tego arkuszu, wybierz jakiś inny.
#TODO: Localize
searching online: Searching online...
#TODO: Localize
searching online fail: Not found online
#TODO: Localize
found online downloading: Found online! Downloading...
#TODO: Localize
found online installing: Found online! Installing...
#TODO: Localize
found online fail: Installation failed
# preferences dialog
language: Język
@@ -958,6 +968,10 @@ button:
upgrade group: &Uaktualnij wszystkie
remove group: &Usuń wszystkie
# stylesheet not found dialog
#TODO: Localize
find package online: Search Online
############################################################## Titles in the GUI
title:
# window titles
@@ -1121,6 +1135,12 @@ error:
file not found package like:
Nie znaleziono pliku: '%s' w paczce '%s'
Jeśli próbujesz otworzyć plik z innej paczki, użyj "/paczka/plik"
#TODO: Localize
file not found package like init:
File not found: '%s' in package '%s'
If this folder is empty or unused, delete it.
#TODO: Localize
package name parse error: Unable to parse package name '%s'
file parse error:
Błąd parsowania pliku: '%s'
%s
+19 -6
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8
mse version: 2.6.0
installer group: Magic Set Editor/translations/portuguese brazilian
full name: Português do Brasil (Brazilian Portuguese)
version: 2026-02-28
@@ -21,7 +21,7 @@ menu:
export images: Todas as I&magens dos Cards...
export apprentice: &Apprentice...
export mws: Magic &Workstation...
check updates: &Atualizações...
check updates: &Atualizações / Novas folhas de estilo...
print preview: V&isualização da Imprensão...
print: &Imprimir... Ctrl+P
reload data: Recarregar Dados Ctrl+F5
@@ -582,8 +582,14 @@ label:
# stylesheet not found dialog
stylesheet not found:
A Edição está tentando abrir a folha de estilo "%s".
Esta folha de estilo não é compatível com o sistema padrão. Por favor escolha uma folha de estilo alternativa.
A Edição está tentando abrir a folha de estilo "%s".
Esta folha de estilo não é compatível com o sistema padrão.
Selecione uma alternativa ou procure-a online.
searching online: Pesquisando online...
searching online fail: Não encontrado online
found online downloading: Encontrado online! Baixando...
found online installing: Encontrado online! Instalando...
found online fail: Falha na instalação
# preferences dialog
language: Linguagem
@@ -837,6 +843,9 @@ button:
upgrade group: &Atualizar o grupo
remove group: &Remover o grupo
# stylesheet not found dialog
find package online: Pesquisar online
############################################################## Titles in the GUI
title:
# window titles
@@ -981,10 +990,14 @@ action:
############################################################## Error messages
error:
# file related
file not found: O arquivo não foi encontrado: '%s' em pacotes '%s'
file not found: O arquivo não foi encontrado: '%s' no pacote '%s'
file not found package like:
Arquivo nao encontrado: '%s' in package '%s'
Arquivo nao encontrado: '%s' no pacote '%s'
Se você está tentando abrir um arquivo de outro pacote, use "/package/filename"
file not found package like init:
Arquivo nao encontrado: '%s' no pacote '%s'
Se esta pasta estiver vazia ou não for usada, exclua-a.
package name parse error: Não foi possível analisar o nome do pacote '%s'
file parse error:
Erro ao analisar o arquivo: '%s'
%s
+21 -1
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8
mse version: 2.6.0
installer group: Magic Set Editor/translations/russian
full name: Русский (Russian)
version: 2026-02-28
@@ -648,6 +648,16 @@ label:
stylesheet not found:
Сет, который ты пытаешься открыть использует стиль "%s".
Этого стиля не найдено в твоей системе, выбери альтернативу
#TODO: Localize
searching online: Searching online...
#TODO: Localize
searching online fail: Not found online
#TODO: Localize
found online downloading: Found online! Downloading...
#TODO: Localize
found online installing: Found online! Installing...
#TODO: Localize
found online fail: Installation failed
# preferences dialog
language: Язык
@@ -946,6 +956,10 @@ button:
upgrade group: Обновить все
remove group: Удалить все
# stylesheet not found dialog
#TODO: Localize
find package online: Search Online
############################################################## Titles in the GUI
title:
# window titles
@@ -1114,6 +1128,12 @@ error:
file not found package like:
File not found: '%s' in package '%s'
If you are trying to open a file from another package, use "/package/filename"
#TODO: Localize
file not found package like init:
File not found: '%s' in package '%s'
If this folder is empty or unused, delete it.
#TODO: Localize
package name parse error: Unable to parse package name '%s'
file parse error:
Error while parsing file: '%s'
%s
+1 -1
View File
@@ -640,8 +640,8 @@ ApprenticeExportWindow::ApprenticeExportWindow(Window* parent, const SetP& set)
s->Add(new wxStaticText(this, -1, _HELP_( "set code")), 0, wxALL, 4);
s->AddSpacer(4);
s->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | (wxALL & ~wxTOP), 8);
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
}
void ApprenticeExportWindow::onApprenticeBrowse(wxCommandEvent& ev) {
+22
View File
@@ -16,6 +16,7 @@
#include <util/io/package_manager.hpp>
#include <util/platform.hpp>
#include <gui/util.hpp> // load_resource_image
#include <wx/webrequest.h>
#include <wx/filename.h>
#include <wx/wfstream.h>
#include <wx/zipstrm.h>
@@ -319,6 +320,27 @@ void InstallablePackage::determineStatus() {
}
}
bool InstallablePackage::ensureIsDownloaded() {
if (!installer) return true; // Nothing to download
if (installer->installer) return true; // Already loaded
if (installer->installer_url.empty()) return false; // No URL
// download installer
wxWebRequestSync request = wxWebSessionSync::GetDefault().CreateRequest(installer->installer_url);
auto const result = request.Execute();
if (!result) {
throw Error(_ERROR_2_("can't download installer", description->name, installer->installer_url));
}
wxInputStream* is(request.GetResponse().GetStream());
installer->installer_file = wxFileName::CreateTempFileName(_("mse-installer"));
wxFileOutputStream os(installer->installer_file);
os.Write(*is);
os.Close();
// open installer
installer->installer = make_intrusive<Installer>();
installer->installer->open(installer->installer_file);
return true;
}
bool InstallablePackage::willBeInstalled() const {
return has(PACKAGE_ACT_INSTALL) ||
(has(PACKAGE_INSTALLED) && !has(PACKAGE_ACT_REMOVE));
+2 -1
View File
@@ -152,7 +152,8 @@ public:
int old_automatic;
void determineStatus();
bool ensureIsDownloaded();
/// After the action, will the package be installed?
bool willBeInstalled() const;
+3 -3
View File
@@ -202,11 +202,11 @@ void Set::validate(Version file_app_version) {
*/
// we want at least one card
if (cards.empty()) cards.push_back(make_intrusive<Card>(*game));
if (cards.empty()) cards.push_back(make_intrusive<Card>(*game));
// build uid map
buildUIDMap();
// update scripts
script_manager->updateAll();
// build uid map
buildUIDMap();
// update_cards_scripts
// first apply all the stylesheet scripts that are older than the first game script
// then apply the first game script
+3 -11
View File
@@ -38,21 +38,13 @@ StyleSheetP StyleSheet::byGameAndName(const Game& game, const String& name) {
return package_manager.open<StyleSheet>(full_name);
}
} catch (PackageNotFoundError& e) {
queue_message(MESSAGE_ERROR, _("Missing stylesheet: ") + full_name);
// This causes a freeze when the set contains two cards that use the same missing StyleSheet, and the second one has styling_data
// Also, it's probably better to ask the user for an alternative for each missing StyleSheet individually
//if (stylesheet_for_reading()) {
// // we already have a stylesheet higher up, so just return a null pointer
// return StyleSheetP();
//}
// load an alternative stylesheet
StyleSheetP ss = select_stylesheet(game, name);
StyleSheetP ss = select_stylesheet(game, full_name);
if (ss) {
stylesheet_alternatives[full_name] = ss->relativeFilename();
return ss;
} else {
queue_message(MESSAGE_ERROR, _("Missing stylesheet: ") + full_name);
throw e;
}
}
@@ -103,8 +95,8 @@ void mark_dependency_value(const StyleSheet& stylesheet, const Dependency& dep)
IMPLEMENT_REFLECTION(StyleSheet) {
REFLECT(game);
REFLECT_BASE(Packaged);
REFLECT(game);
REFLECT(card_width);
REFLECT(card_height);
REFLECT(card_dpi);
+2 -2
View File
@@ -816,8 +816,8 @@ ImportedImage::ImportedImage(Set* set, const String& filepath) {
// determine save name
loadpath = filepath;
savename = normalize_internal_filename(loadpath);
savename.Replace(":", "-");
savename.Replace("/", "-");
savename.Replace(_(":"), _("-"));
savename.Replace(_("/"), _("-"));
// does the file pointed to by filepath exist?
if (!wxFileName(loadpath, wxPATH_UNIX).FileExists()) {
+1 -1
View File
@@ -48,8 +48,8 @@ AddCSVWindow::AddCSVWindow(Window* parent, const SetP& set, bool sizer)
s2->Add(CreateButtonSizer(wxOK | wxCANCEL), 1, wxEXPAND, 8);
s->Add(s2, 0, wxEXPAND | wxALL, 12);
file_browse->SetFocus();
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
SetSize(500, 110);
}
}
+1 -1
View File
@@ -59,8 +59,8 @@ AddJSONWindow::AddJSONWindow(Window* parent, const SetP& set, bool sizer)
s2->Add(CreateButtonSizer(wxOK | wxCANCEL), 1, wxEXPAND, 8);
s->Add(s2, 0, wxEXPAND | wxALL, 12);
file_browse->SetFocus();
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
SetSize(500, 110);
}
}
+1 -1
View File
@@ -199,8 +199,8 @@ AutoReplaceWindow::AutoReplaceWindow(Window* parent, const Game& game)
s4->Add(defaults, 0, wxALL & ~wxRIGHT, 8);
s4->Add(CreateButtonSizer(wxOK | wxCANCEL), 1, wxALL, 8);
s->Add(s4, 0, wxEXPAND);
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
// Set default size
SetSize(350, 450);
// initialize values
+1 -1
View File
@@ -85,8 +85,8 @@ BulkModificationWindow::BulkModificationWindow(Window* parent, const SetP& set,
s1->AddButton(new wxButton(this, wxID_CANCEL));
s1->Realize();
s->Add(s1, 1, wxEXPAND | wxALL, 12);
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
SetSize(600, 400);
Layout();
}
+2 -2
View File
@@ -20,7 +20,7 @@
// ----------------------------------------------------------------------------- : ExportCardSelectionChoice
CardLinkWindow::CardLinkWindow(Window* parent, const SetP& set, const CardP& selected_card, bool sizer)
: wxDialog(parent, wxID_ANY, _TITLE_("link cards"), wxPoint(400,-1), wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
: wxDialog(parent, wxID_ANY, _TITLE_("link cards"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
, set(set), parent(parent), selected_card(selected_card)
{
// init controls
@@ -53,8 +53,8 @@ CardLinkWindow::CardLinkWindow(Window* parent, const SetP& set, const CardP& sel
s2->Add(sel_none, 0, wxEXPAND | wxRIGHT, 8);
s2->Add(CreateButtonSizer(wxOK | wxCANCEL), 1, wxEXPAND, 8);
s->Add(s2, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
SetSize(600,500);
}
}
+1 -1
View File
@@ -140,8 +140,8 @@ CardSelectWindow::CardSelectWindow(Window* parent, const SetP& set, const String
s2->Add(sel_none, 0, wxEXPAND | wxRIGHT, 8);
s2->Add(CreateButtonSizer(wxOK | wxCANCEL), 1, wxEXPAND, 8);
s->Add(s2, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
SetSize(600,500);
}
}
+2 -1
View File
@@ -533,7 +533,8 @@ bool CardListBase::canLink() const {
return card->findFreeLink(card->uid, set->card_uids) >= 0;
}
bool CardListBase::doLink() {
CardLinkWindow wnd(this, set, getCard());
CardLinkWindow wnd(this, set, getCard());
wnd.CentreOnParent();
if (wnd.ShowModal() == wxID_OK) {
// The actual linking is done in this window's onOk function
return true;
+1 -1
View File
@@ -34,8 +34,8 @@ CardListColumnSelectDialog::CardListColumnSelectDialog(Window* parent, const Gam
s2->Add(s3, 0, wxEXPAND | (wxALL & ~wxTOP), 4);
s->Add(s2 , 1, wxEXPAND | wxALL, 4);
s->Add(CreateButtonSizer(wxOK | wxCANCEL) , 0, wxEXPAND | wxALL, 8);
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
// Set default size
SetSize(350, 450);
// Initialize order list
+2 -1
View File
@@ -58,7 +58,8 @@ void TextCtrl::updateSize() {
ValueViewer& viewer = *viewers.front();
viewer.bounding_box.width = cs.GetWidth() - 2;
viewer.bounding_box.height = cs.GetHeight() - 2;
viewers.front()->getEditor()->determineSize(true);
viewers.front()->getEditor()->determineSize(true);
InvalidateBestSize();
}
void TextCtrl::setValue(String* value, bool untagged) {
+3 -3
View File
@@ -68,12 +68,12 @@ public:
/// Show a dialog to inform the user that updates are available (if there are any)
/// Call check_updates first. Call this function from an onIdle loop
inline void show_update_dialog(Window* parent) {
inline void show_update_dialog(Window* set_window) {
if (shown_dialog || check_status != FOUND) return; // we already have the latest version, or this has already been displayed.
shown_dialog = true;
wxMessageDialog dial = wxMessageDialog(parent, _LABEL_("updates found"), _TITLE_("updates available"), wxYES_NO);
wxMessageDialog dial = wxMessageDialog(set_window, _LABEL_("updates found"), _TITLE_("updates available"), wxYES_NO);
if (dial.ShowModal() == wxID_YES) {
(new PackagesWindow(parent))->Show();
(new PackagesWindow(set_window))->Show();
}
}
+2 -2
View File
@@ -44,11 +44,11 @@ HtmlExportWindow::HtmlExportWindow(Window* parent, const SetP& set, const Export
s2->Add(s3, 7, wxEXPAND | wxLEFT, 8);
s->Add(s2, 1, wxEXPAND | wxALL, 4);
s->Add(CreateButtonSizer(wxOK | wxCANCEL) , 0, wxEXPAND | wxALL, 8);
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
SetSize(700,500);
// list
list->showData<ExportTemplate>(set->game->name() + _("-*"));
list->showData<ExportTemplate>(set->game->name() + _("*"));
list->select(settings.gameSettingsFor(*set->game).default_export);
}
+1 -1
View File
@@ -229,8 +229,8 @@ ImageSliceWindow::ImageSliceWindow(Window* parent, const Image& source, const St
s5->AddStretchSpacer(1);
s->Add(s5, 0, wxEXPAND);
s->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxALL, 8);
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
// Only now do we allow events to be processed.
initialized = true;
updateControls();
+1 -1
View File
@@ -43,8 +43,8 @@ ImagesExportWindow::ImagesExportWindow(Window* parent, const SetP& set, const Ex
wxSizer* s3 = ExportWindowBase::Create();
s->Add(s3, 1, wxEXPAND | (wxALL & ~wxTOP), 8);
s->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | (wxALL & ~wxTOP), 8);
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
SetSize(500,-1);
}
+121 -18
View File
@@ -10,6 +10,8 @@
#include <gui/new_window.hpp>
#include <gui/control/gallery_list.hpp>
#include <gui/control/package_list.hpp>
#include <gui/downloadable_installers.hpp>
#include <data/installer.hpp>
#include <data/game.hpp>
#include <data/stylesheet.hpp>
#include <data/set.hpp>
@@ -56,8 +58,8 @@ NewSetWindow::NewSetWindow(Window* parent)
s->Add(s3, wxSizerFlags().Expand().Border(wxALL, 6));
s->Add(stylesheet_list, 0, wxEXPAND | (wxALL & ~wxTOP), 4);
s->Add(CreateButtonSizer(wxOK | wxCANCEL) , 0, wxEXPAND | wxALL, 8);
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
// Resize
Layout();
wxSize min_size = GetSizer()->GetMinSize() + GetSize() - GetClientSize();
@@ -177,10 +179,15 @@ StyleSheetP select_stylesheet(const Game& game, const String& failed_name) {
SelectStyleSheetWindow::SelectStyleSheetWindow(Window* parent, const Game& game, const String& failed_name)
: wxDialog(parent, wxID_ANY, _TITLE_("select stylesheet"), wxDefaultPosition, wxSize(830,320), wxDEFAULT_DIALOG_STYLE)
, game(game)
, failed_name(failed_name)
{
wxBusyCursor wait;
// init controls
stylesheet_list = new PackageList (this, ID_STYLESHEET_LIST);
// init controls
ok_button = new wxButton (this, wxID_OK);
cancel_button = new wxButton (this, wxID_CANCEL);
find_online_button = new wxButton (this, ID_DOWNLOAD_STYLESHEET, _BUTTON_("find package online"));
stylesheet_list = new PackageList (this, ID_STYLESHEET_LIST);
find_online_status_text = new wxStaticText(this, wxID_ANY, _(""));
wxStaticText* description = new wxStaticText(this, ID_GAME_LIST, _LABEL_1_("stylesheet not found", failed_name));
wxStaticText* stylesheet_text = new wxStaticText(this, ID_STYLESHEET_LIST, _LABEL_("style type"));
@@ -195,18 +202,26 @@ SelectStyleSheetWindow::SelectStyleSheetWindow(Window* parent, const Game& game,
s2->AddStretchSpacer();
s2->Add(stylesheet_filter, 1, wxRIGHT, 4);
s->Add(s2, wxSizerFlags().Expand().Border(wxALL, 6));
s->Add(stylesheet_list, 0, wxEXPAND | (wxALL & ~wxTOP), 4);
s->Add(CreateButtonSizer(wxOK | wxCANCEL) , 0, wxEXPAND | wxALL, 8);
s->SetSizeHints(this);
s->Add(stylesheet_list, 0, wxEXPAND | (wxALL & ~wxTOP), 4);
wxBoxSizer* s3 = new wxBoxSizer(wxHORIZONTAL);
s3->Add(find_online_button, 0, wxRIGHT, 8);
s3->Add(find_online_status_text, 1, wxALIGN_CENTER_VERTICAL);
s3->AddStretchSpacer();
s3->Add(ok_button, 0, wxRIGHT, 4);
s3->Add(cancel_button, 0);
s->Add(s3, 0, wxEXPAND | wxALL, 8);
SetSizer(s);
s->SetSizeHints(this);
// init list
stylesheet_list->showData<StyleSheet>(game.name() + _("-*"));
stylesheet_list->showData<StyleSheet>(game.name() + _("*"));
stylesheet_list->select(settings.gameSettingsFor(game).default_stylesheet);
// Resize
Layout();
wxSize min_size = GetSizer()->GetMinSize() + GetSize() - GetClientSize();
SetSize(830,min_size.y);
UpdateWindowUI(wxUPDATE_UI_RECURSE);
UpdateWindowUI(wxUPDATE_UI_RECURSE);
// start downloading the installer list
downloadable_installers.download();
}
void SelectStyleSheetWindow::onStyleSheetSelect(wxCommandEvent&) {
@@ -226,7 +241,88 @@ void SelectStyleSheetWindow::onStylesheetFilterUpdate(wxCommandEvent&) {
else {
stylesheet_list->setFilter(stylesheet_filter->getFilter<PackageData>());
}
}
}
void SelectStyleSheetWindow::onFindOnline(wxCommandEvent&) {
if (searching_online) return;
searching_online = true;
find_online_status_text->SetLabel(_LABEL_("searching online"));
find_online_button->Enable(false);
//downloadable_installers.download();
}
void SelectStyleSheetWindow::tryAutoInstall() {
auto_installing = true;
searching_online = false;
wxBusyCursor busy;
// search for missing stylesheet
InstallablePackages packages;
package_manager.findAllInstalledPackages(packages);
FOR_EACH(inst, downloadable_installers.installers) {
merge(packages, inst);
}
FOR_EACH(p, packages) {
if (!p) continue;
p->determineStatus();
}
InstallablePackageP target;
FOR_EACH(p, packages) {
if (!p || !p->description) continue;
if (p->description->name == failed_name) {
target = p;
break;
}
}
if (!target) {
find_online_status_text->SetLabel(_LABEL_("searching online fail"));
auto_installing = false;
return;
}
try {
// update UI
find_online_status_text->SetLabel(_LABEL_("found online downloading"));
ok_button->Enable(false);
cancel_button->Enable(false);
stylesheet_list->Enable(false);
stylesheet_filter->Enable(false);
Layout();
Refresh();
Update();
wxSafeYield(this, true);
// resolve dependencies
PackageAction where = is_install_local(settings.install_type) ? PACKAGE_ACT_LOCAL : PACKAGE_ACT_GLOBAL;
bool action_ok = set_package_action(packages, target, PACKAGE_ACT_INSTALL | where);
if (!action_ok) throw Error(_("can't resolve dependencies"));
// download stylesheet and dependencies
FOR_EACH(p, packages) {
if (!p->has(PACKAGE_ACT_INSTALL)) continue;
p->ensureIsDownloaded();
}
// update UI
find_online_status_text->SetLabel(_LABEL_("found online installing"));
Layout();
Refresh();
Update();
wxSafeYield(this, true);
// install stylesheet and dependencies
FOR_EACH(p, packages) {
if (!p->has(PACKAGE_ACT_INSTALL)) continue;
bool package_ok = package_manager.install(*p);
if (!package_ok) throw Error(_("install package failed"));
}
// auto select stylesheet and exit
stylesheet = StyleSheet::byGameAndName(game, failed_name);
EndModal(wxID_OK);
} catch (const Error& e) {
handle_error(e);
auto_installing = false;
find_online_status_text->SetLabel(_LABEL_("found online fail"));
ok_button->Enable(true);
cancel_button->Enable(true);
stylesheet_list->Enable(true);
stylesheet_filter->Enable(true);
}
}
void SelectStyleSheetWindow::OnOK(wxCommandEvent&) {
done();
@@ -245,22 +341,29 @@ void SelectStyleSheetWindow::done() {
void SelectStyleSheetWindow::onUpdateUI(wxUpdateUIEvent& ev) {
switch (ev.GetId()) {
case wxID_OK:
ev.Enable(stylesheet_list->hasSelection());
if (!auto_installing) ev.Enable(stylesheet_list->hasSelection());
break;
}
}
void SelectStyleSheetWindow::onIdle(wxIdleEvent& ev) {
// Stuff that must be done in the main thread
//handle_pending_errors(); // errors are ignored until set window is shown
if (searching_online && !auto_installing) {
// still downloading?
if (!downloadable_installers.download()) {
return;
}
// installer list ready
tryAutoInstall();
}
}
BEGIN_EVENT_TABLE(SelectStyleSheetWindow, wxDialog)
EVT_GALLERY_SELECT (ID_STYLESHEET_LIST, SelectStyleSheetWindow::onStyleSheetSelect)
EVT_GALLERY_ACTIVATE(ID_STYLESHEET_LIST, SelectStyleSheetWindow::onStyleSheetActivate)
EVT_COMMAND_RANGE(ID_STYLESHEET_FILTER, ID_STYLESHEET_FILTER, wxEVT_COMMAND_TEXT_UPDATED, SelectStyleSheetWindow::onStylesheetFilterUpdate)
EVT_BUTTON (wxID_OK, SelectStyleSheetWindow::OnOK)
EVT_UPDATE_UI (wxID_ANY, SelectStyleSheetWindow::onUpdateUI)
EVT_IDLE ( SelectStyleSheetWindow::onIdle)
EVT_GALLERY_SELECT (ID_STYLESHEET_LIST, SelectStyleSheetWindow::onStyleSheetSelect)
EVT_GALLERY_ACTIVATE(ID_STYLESHEET_LIST, SelectStyleSheetWindow::onStyleSheetActivate)
EVT_COMMAND_RANGE (ID_STYLESHEET_FILTER, ID_STYLESHEET_FILTER, wxEVT_COMMAND_TEXT_UPDATED, SelectStyleSheetWindow::onStylesheetFilterUpdate)
EVT_BUTTON (ID_DOWNLOAD_STYLESHEET, SelectStyleSheetWindow::onFindOnline)
EVT_BUTTON (wxID_OK, SelectStyleSheetWindow::OnOK)
EVT_UPDATE_UI (wxID_ANY, SelectStyleSheetWindow::onUpdateUI)
EVT_IDLE ( SelectStyleSheetWindow::onIdle)
END_EVENT_TABLE ()
+17 -7
View File
@@ -81,22 +81,32 @@ private:
const Game& game;
// gui items
PackageList* stylesheet_list;
PackageList* stylesheet_list;
FilterCtrl* stylesheet_filter;
String stylesheet_filter_value;
wxButton* ok_button, *cancel_button;
wxButton* find_online_button;
wxStaticText* find_online_status_text;
bool searching_online = false;
bool auto_installing = false;
String failed_name;
FilterCtrl* stylesheet_filter;
String stylesheet_filter_value;
// --------------------------------------------------- : events
void onStyleSheetSelect (wxCommandEvent&);
void onStyleSheetActivate(wxCommandEvent&);
void onStylesheetFilterUpdate(wxCommandEvent&);
void onFindOnline(wxCommandEvent&);
virtual void OnOK(wxCommandEvent&);
void onUpdateUI(wxUpdateUIEvent&);
void onIdle(wxIdleEvent&);
void onIdle(wxIdleEvent&);
void tryAutoInstall();
// we are done, close the window
void done();
};
+16 -24
View File
@@ -18,7 +18,6 @@
#include <data/settings.hpp>
#include <gfx/gfx.hpp>
#include <wx/wfstream.h>
#include <wx/webrequest.h>
#include <wx/dcbuffer.h>
#include <wx/progdlg.h>
#include <wx/tglbtn.h>
@@ -131,9 +130,7 @@ END_EVENT_TABLE()
// ----------------------------------------------------------------------------- : PackagesWindow
enum Action {
KEEP, INSTALL, UPGRADE, REMOVE
};
DEFINE_EVENT_TYPE(EVENT_PACKAGE_LIST_CHANGED);
PackagesWindow::PackagesWindow(Window* parent, bool download_package_list)
: waiting_for_list(download_package_list)
@@ -239,7 +236,7 @@ void PackagesWindow::onActionChange(wxCommandEvent& ev) {
);
package_list->Refresh(false);
UpdateWindowUI(wxUPDATE_UI_RECURSE);
}
}
void PackagesWindow::onOk(wxCommandEvent& ev) {
// count number of packages to change
@@ -261,7 +258,7 @@ void PackagesWindow::onOk(wxCommandEvent& ev) {
}
}
// anything to do?
if (!to_change) {
if (!to_change && !app_change) {
ev.Skip();
return;
}
@@ -281,8 +278,6 @@ void PackagesWindow::onOk(wxCommandEvent& ev) {
this,
wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_SMOOTH | wxSTAY_ON_TOP
);
// Clear package list
package_manager.reset();
// Download installers
int package_pos = 0, step = 0;
FOR_EACH(ip, installable_packages) {
@@ -290,21 +285,8 @@ void PackagesWindow::onOk(wxCommandEvent& ev) {
if (ip->has(PACKAGE_ACT_INSTALL) && ip->installer && !ip->installer->installer) {
if (!progress.Update(step++, String::Format(_ERROR_("downloading updates"), ++package_pos, to_download))) {
return; // aborted
}
// download installer
wxWebRequestSync request = wxWebSessionSync::GetDefault().CreateRequest(ip->installer->installer_url);
auto const result = request.Execute();
if (!result) {
throw Error(_ERROR_2_("can't download installer", ip->description->name, ip->installer->installer_url));
}
wxInputStream* is(request.GetResponse().GetStream());
ip->installer->installer_file = wxFileName::CreateTempFileName(_("mse-installer"));
wxFileOutputStream os(ip->installer->installer_file);
os.Write(*is);
os.Close();
// open installer
ip->installer->installer = make_intrusive<Installer>();
ip->installer->installer->open(ip->installer->installer_file);
}
ip->ensureIsDownloaded();
}
}
// Install stuff
@@ -369,6 +351,8 @@ void PackagesWindow::onOk(wxCommandEvent& ev) {
// }
//}
}
// Notify that packages have changed
sendEvent();
// Continue event propagation into the dialog window so that it closes.
ev.Skip();
//%% TODO: will we delete packages?
@@ -421,6 +405,9 @@ void PackagesWindow::onUpdateUI(wxUpdateUIEvent& ev) {
package_list->allSelectedPackages([&](const InstallablePackageP& p) {
return p->has(PACKAGE_ACT_REMOVE | where) ||
(!p->has(PACKAGE_INSTALLED) && !p->has(PACKAGE_ACT_INSTALL));
}) &&
package_list->anySelectedPackage([&](const InstallablePackageP& p) {
return p->has(PACKAGE_ACT_REMOVE | where);
})
);
w->Enable(
@@ -455,7 +442,12 @@ bool PackagesWindow::checkInstallerList(bool refresh) {
UpdateWindowUI(wxUPDATE_UI_RECURSE);
}
return true;
}
}
void PackagesWindow::sendEvent() {
wxCommandEvent ev(EVENT_PACKAGE_LIST_CHANGED, GetId());
wxPostEvent(GetParent(), ev);
}
BEGIN_EVENT_TABLE(PackagesWindow, wxDialog)
EVT_LISTBOX (ID_PACKAGE_LIST, PackagesWindow::onPackageSelect)
+3 -1
View File
@@ -50,6 +50,8 @@ private:
/// Check whether we have downloaded the list of installers
/** If the download is (partially) complete, update the installable_packages list */
bool checkInstallerList(bool refresh = true);
bool checkInstallerList(bool refresh = true);
/// Notify that the package list has changed
void sendEvent();
};
+10 -7
View File
@@ -125,8 +125,8 @@ PreferencesWindow::PreferencesWindow(Window* parent)
s->Add(nb, 1, wxEXPAND | (wxALL & ~wxBOTTOM), 8);
s->AddSpacer(4);
s->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | (wxALL & ~wxTOP), 8);
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
}
void PreferencesWindow::onOk(wxCommandEvent&) {
@@ -177,7 +177,6 @@ GlobalPreferencesPage::GlobalPreferencesPage(Window* parent)
dark_mode->SetSelection((int)settings.dark_mode_type);
// init sizer
wxSizer* s = new wxBoxSizer(wxVERTICAL);
s->SetSizeHints(this);
wxSizer* s2 = new wxStaticBoxSizer(wxVERTICAL, this, _LABEL_("language"));
s2->Add(new wxStaticText(this, wxID_ANY, _LABEL_("app language")), 0, wxALL, 4);
s2->Add(language, 0, wxEXPAND | (wxALL & ~wxTOP), 4);
@@ -191,6 +190,7 @@ GlobalPreferencesPage::GlobalPreferencesPage(Window* parent)
s4->Add(new wxStaticText(this, wxID_ANY, _HELP_( "app language")), 0, wxALL, 4);
s->Add(s4, 0, wxEXPAND | wxALL, 8);
SetSizer(s);
s->SetSizeHints(this);
}
void GlobalPreferencesPage::store() {
@@ -243,8 +243,8 @@ DisplayPreferencesPage::DisplayPreferencesPage(Window* parent)
s3->Add(new wxStaticText(this, wxID_ANY, _LABEL_("percent of normal")),1, wxALL & ~wxRIGHT, 4);
s2->Add(s3, 0, wxEXPAND | wxALL, 4);
s->Add(s2, 0, wxEXPAND | wxALL, 8);
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
}
void DisplayPreferencesPage::store() {
@@ -342,8 +342,8 @@ TransfersPreferencesPage::TransfersPreferencesPage(Window* parent) : Preferences
s->Add(s2, 0, wxEXPAND | wxALL, 8);
s->Add(s5, 0, wxEXPAND | wxALL, 8);
export_scale->SetFocus();
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
}
void TransfersPreferencesPage::store() {
@@ -375,8 +375,8 @@ DirsPreferencesPage::DirsPreferencesPage(Window* parent)
s3->Add(ab, 0, wxEXPAND);
s2->Add(s3, 0, wxEXPAND | (wxALL & ~wxTOP), 4);
s->Add(s2, 0, wxEXPAND | wxALL, 8);
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
}
void DirsPreferencesPage::store() {
@@ -440,14 +440,17 @@ void UpdatePreferencesPage::store() {
else settings.check_updates_what = CHECK_EVERYTHING;
}
void UpdatePreferencesPage::onCheckUpdatesNow(wxCommandEvent&) {
void UpdatePreferencesPage::onCheckUpdatesNow(wxCommandEvent&) {
downloadable_installers.shown_dialog = true;
downloadable_installers.check_updates_now(false);
if (downloadable_installers.check_status == DownloadableInstallerList::CheckStatus::FAILED) {
wxMessageBox(_ERROR_("checking updates failed"), _TITLE_("update check"), wxICON_ERROR | wxOK);
} else if (downloadable_installers.check_status == DownloadableInstallerList::CheckStatus::NOT_FOUND) {
wxMessageBox(_ERROR_("no updates"), _TITLE_("update check"), wxICON_INFORMATION | wxOK);
} else {
(new PackagesWindow(GetParent()))->Show();
wxWindow* set_window = this;
while (set_window->GetParent()) set_window = set_window->GetParent();
(new PackagesWindow(set_window))->Show();
}
}
+1 -1
View File
@@ -118,8 +118,8 @@ CardsPanel::CardsPanel(Window* parent, int id)
link_grid_4->Add(link_viewer_4, wxGBPosition(1, 0), wxGBSpan(1, 2));
s->Add(s_left, 0, wxEXPAND | wxRIGHT, 2);
s->Add(splitter, 1, wxEXPAND);
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
// init menus
menuCard = new wxMenu();
+9 -4
View File
@@ -515,8 +515,8 @@ ConsolePanel::ConsolePanel(Window* parent, int id)
// init sizer
wxSizer* s = new wxBoxSizer(wxVERTICAL);
s->Add(splitter, 1, wxEXPAND);
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
// init menus
menuConsole = new wxMenu();
@@ -636,9 +636,14 @@ void ConsolePanel::exec(String const& command) {
set_alpha(image, color.Alpha() / 255.0);
message->bitmap = wxBitmap(image);
} else {
boost::json::value jresult = mse_to_json(result, set.get(), true);
if (jresult.is_null()) message->text = result->toCode();
else message->text = json_pretty_print(jresult);
try {
boost::json::value jresult = mse_to_json(result, set.get(), true);
if (jresult.is_null()) message->text = result->toCode();
else message->text = json_pretty_print(jresult);
}
catch (...) {
message->text = result->toCode();
}
}
messages->add_message(message);
} catch (ScriptError const& e) {
+20 -17
View File
@@ -60,29 +60,32 @@ void KeywordsPanel::initControls() {
sp = new wxBoxSizer(wxVERTICAL);
sp->Add(fixed, 0, wxEXPAND); sp->Show(fixed,false);
wxSizer* s1 = new wxBoxSizer(wxVERTICAL);
s1->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("keyword")+_(":")), 0, wxTOP, 2);
s1->Add(keyword, 1, wxEXPAND | wxTOP, 2);
s1->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("mode")+_(":")), 0, wxTOP, 2);
s1->Add(mode, 0, wxEXPAND | wxTOP, 2);
s1->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("keyword")+_(":")), 0, wxTOP | wxLEFT, 4);
s1->Add(keyword, 0, wxEXPAND | wxTOP | wxLEFT, 4);
sp->Add(s1, 0, wxEXPAND | wxRIGHT, 4);
sp->Add(new wxStaticLine(panel), 0, wxEXPAND | wxTOP | wxBOTTOM, 8);
sp->Add(new wxStaticLine(panel), 0, wxEXPAND | wxTOP | wxBOTTOM, 16);
wxSizer* s9 = new wxBoxSizer(wxVERTICAL);
s9->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("mode")+_(":")), 0, wxTOP | wxLEFT, 4);
s9->Add(mode, 0, wxEXPAND | wxTOP | wxLEFT, 4);
sp->Add(s9, 0, wxEXPAND | wxRIGHT, 4);
sp->Add(new wxStaticLine(panel), 0, wxEXPAND | wxTOP | wxBOTTOM, 16);
wxSizer* s2 = new wxBoxSizer(wxVERTICAL);
s2->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("match")+_(":")), 0);
s2->Add(match, 1, wxEXPAND | wxTOP, 2);
s2->Add(add_param, 0, wxALIGN_LEFT | wxTOP, 2);
s2->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("match")+_(":")), 0, wxTOP | wxLEFT, 4);
s2->Add(match, 0, wxEXPAND | wxTOP | wxLEFT, 4);
s2->Add(add_param, 0, wxALIGN_LEFT | wxTOP | wxLEFT, 4);
sp->Add(s2, 0, wxEXPAND | wxRIGHT, 4);
sp->Add(new wxStaticLine(panel), 0, wxEXPAND | wxTOP | wxBOTTOM, 8);
sp->Add(new wxStaticLine(panel), 0, wxEXPAND | wxTOP | wxBOTTOM, 16);
wxSizer* s3 = new wxBoxSizer(wxVERTICAL);
s3->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("reminder")+_(":")), 0);
s3->Add(reminder, 1, wxEXPAND | wxTOP, 2);
s3->Add(ref_param, 0, wxALIGN_LEFT | wxTOP, 2);
s3->Add(errors, 0, wxEXPAND | wxTOP, 4);
s3->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("reminder")+_(":")), 0, wxTOP | wxLEFT, 4);
s3->Add(reminder, 1, wxEXPAND | wxTOP | wxLEFT, 4);
s3->Add(ref_param, 0, wxALIGN_LEFT | wxTOP | wxLEFT, 4);
s3->Add(errors, 0, wxEXPAND | wxTOP | wxLEFT, 4);
//s3->Add(new wxStaticText(panel, wxID_ANY, _("Example:")), 0, wxTOP, 6);
sp->Add(s3, 1, wxEXPAND | wxRIGHT, 4);
sp->Add(new wxStaticLine(panel), 0, wxEXPAND | wxTOP | wxBOTTOM, 8);
sp->Add(new wxStaticLine(panel), 0, wxEXPAND | wxTOP | wxBOTTOM, 16);
wxSizer* s4 = new wxBoxSizer(wxVERTICAL);
s4->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("rules")+_(":")), 0);
s4->Add(rules, 1, wxEXPAND | wxTOP, 2);
s4->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("rules")+_(":")), 0, wxTOP | wxLEFT, 4);
s4->Add(rules, 1, wxEXPAND | wxTOP | wxLEFT, 4);
sp->Add(s4, 1, wxEXPAND | wxRIGHT, 4);
panel->SetSizer(sp);
// init splitter
@@ -92,8 +95,8 @@ void KeywordsPanel::initControls() {
// init sizer
wxSizer* s = new wxBoxSizer(wxHORIZONTAL);
s->Add(splitter, 1, wxEXPAND);
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
//s->Add(new wxStaticText(this, wxID_ANY, _("Sorry, no keywords for now"),wxDefaultPosition,wxDefaultSize,wxALIGN_CENTER), 1, wxALIGN_CENTER); // TODO: Remove
/* wxSizer* s2 = new wxBoxSizer(wxVERTICAL);
+2 -1
View File
@@ -24,8 +24,9 @@ class SetWindowPanel : public wxPanel, public SetView {
public:
SetWindowPanel(Window* parent, int id, bool autoTabbing = true);
/// We will probably want to respond to set changes
/// We will probably want to respond to set changes or package list changes
virtual void onSetChange() {}
virtual void onPackageListChange() {}
// // --------------------------------------------------- : Meta information
//
+2 -2
View File
@@ -301,8 +301,8 @@ CustomPackDialog::CustomPackDialog(Window* parent, const SetP& set, const PackTy
totals->setGame(set->game);
updateTotals();
// set sizer
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
}
void CustomPackDialog::updateTotals() {
@@ -417,8 +417,8 @@ void RandomPackPanel::initControls() {
s2->Add(s3, 0, wxEXPAND | (wxALL & ~wxTOP), 4);
s2->Add(card_list, 1, wxEXPAND);
s->Add(s2, 1, wxEXPAND, 8);
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
}
RandomPackPanel::~RandomPackPanel() {
+1 -1
View File
@@ -22,8 +22,8 @@ SetInfoPanel::SetInfoPanel(Window* parent, int id)
// init sizer
wxSizer* s = new wxBoxSizer(wxVERTICAL);
s->Add(editor, 1, wxEXPAND, 2);
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
}
void SetInfoPanel::onChangeSet() {
+1 -1
View File
@@ -330,8 +330,8 @@ void StatsPanel::initControls() {
s->Add(categories, 0, wxEXPAND | wxRIGHT, 2);
#endif
s->Add(splitter, 1, wxEXPAND);
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
// init menu
menuGraph = new wxMenu();
+22 -11
View File
@@ -55,8 +55,8 @@ void StylePanel::initControls() {
s4->Add(editor, 2, wxEXPAND, 0);
s2->Add(s4, 1, wxEXPAND | wxALL, 2);
s->Add(s2, 1, wxEXPAND, 8);
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
}
void StylePanel::initUI(wxToolBar* tb, wxMenuBar* mb) {
@@ -95,13 +95,31 @@ bool StylePanel::Layout() {
void StylePanel::onChangeSet() {
if (!isInitialized()) return;
list->showData<StyleSheet>(set->game->name() + _("-*"));
list->showData<StyleSheet>(set->game->name() + _("*"));
list->select(set->stylesheet->name(), false);
editor->setSet(set);
preview->setSet(set);
card = CardP();
use_for_all->Enable(false);
}
}
void StylePanel::onPackageListChange() {
if (!isInitialized()) return;
if (!list) return;
list->showData<StyleSheet>(set->game->name() + _("*"));
onFilterChange();
}
void StylePanel::onFilterChange() {
if (list->hasSelection()) {
StyleSheetP existingStylesheetSelection = list->getSelection<StyleSheet>(false);
list->setFilter(stylesheet_filter->getFilter<PackageData>());
list->select(existingStylesheetSelection->name());
}
else {
list->setFilter(stylesheet_filter->getFilter<PackageData>());
}
}
void StylePanel::onAction(const Action& action, bool undone) {
if (!isInitialized()) return;
@@ -139,14 +157,7 @@ void StylePanel::onAction(const Action& action, bool undone) {
}
void StylePanel::onStylesheetFilterUpdate(wxCommandEvent&) {
if (list->hasSelection()) {
StyleSheetP existingStylesheetSelection = list->getSelection<StyleSheet>(false);
list->setFilter(stylesheet_filter->getFilter<PackageData>());
list->select(existingStylesheetSelection->name());
}
else {
list->setFilter(stylesheet_filter->getFilter<PackageData>());
}
onFilterChange();
}
// ----------------------------------------------------------------------------- : Selection
+5 -3
View File
@@ -22,14 +22,16 @@ class StylingEditor;
class StylePanel : public SetWindowPanel {
public:
StylePanel(Window* parent, int id);
void onChangeSet() override;
void onPackageListChange() override;
void onFilterChange();
void onAction(const Action&, bool undone) override;
// --------------------------------------------------- : UI
void initUI(wxToolBar*, wxMenuBar*) override;
// --------------------------------------------------- : Clipboard
bool canCut() const override;
bool canCopy() const override;
@@ -61,7 +63,7 @@ private:
void onUseCustom(wxCommandEvent&);
void onStylesheetFilterUpdate(wxCommandEvent&);
/// Determine the best size for the list of stylesheets based on available space
void updateListSize();
bool Layout() override;
+7
View File
@@ -856,6 +856,12 @@ void SetWindow::onMenuOpen(wxMenuEvent& ev) {
void SetWindow::onIdle(wxIdleEvent& ev) {
// Stuff that must be done in the main thread
downloadable_installers.show_update_dialog(this);
}
void SetWindow::onPackageListChange(wxCommandEvent&) {
FOR_EACH(p, panels) {
p->onPackageListChange();
}
}
// ----------------------------------------------------------------------------- : Event table
@@ -917,4 +923,5 @@ BEGIN_EVENT_TABLE(SetWindow, wxFrame)
EVT_CARD_SELECT (wxID_ANY, SetWindow::onCardSelect)
EVT_CARD_ACTIVATE (wxID_ANY, SetWindow::onCardActivate)
EVT_SIZE_CHANGE (wxID_ANY, SetWindow::onSizeChange)
EVT_COMMAND (wxID_ANY, EVENT_PACKAGE_LIST_CHANGED, SetWindow::onPackageListChange)
END_EVENT_TABLE ()
+3 -1
View File
@@ -176,6 +176,8 @@ private:
void onIdle (wxIdleEvent&);
void onSizeChange (wxCommandEvent&);
void onSizeChange (wxCommandEvent&);
void onPackageListChange (wxCommandEvent&);
};
+11 -3
View File
@@ -665,12 +665,13 @@ void TextValueEditor::draw(RotatedDC& dc) {
}
}
void TextValueEditor::redrawSelection(size_t old_selection_start_i, size_t old_selection_end_i, bool old_drop_down_shown) {
void TextValueEditor::redrawSelection(size_t old_selection_start_i, size_t old_selection_end_i, bool old_drop_down_shown) {
// Hide caret
if (isCurrent()) {
wxCaret* caret = editor().GetCaret();
if (caret->IsVisible()) caret->Hide();
}
}
#ifdef __WXMSW__
// Destroy the clientDC before reshowing the caret, prevent flicker on MSW
{
// Move selection
@@ -701,7 +702,14 @@ void TextValueEditor::redrawSelection(size_t old_selection_start_i, size_t old_s
// redraw drop down indicators
drawWordListIndicators(dc, true);
}
}
}
#else
scroll_with_cursor = true;
if (ensureCaretVisible()) {
updateScrollbar();
}
redraw();
#endif
if (isCurrent()) {
showCaret();
}
+1 -1
View File
@@ -27,8 +27,8 @@ WebRequestWindow::WebRequestWindow(const String& url, bool sizer)
s->Add(address, 0, (wxALL & ~wxTOP), 4);
s->Add(gauge, 0, wxEXPAND | wxALL, 8);
s->Add(CreateButtonSizer(wxCANCEL), 1, wxEXPAND, 8);
s->SetSizeHints(this);
SetSizer(s);
s->SetSizeHints(this);
}
// create web request
+5 -3
View File
@@ -124,8 +124,9 @@ void WelcomeWindow::onOpenSet(wxCommandEvent&) {
wxBusyCursor wait;
try {
close(import_set(dlg->GetPath()));
} catch (Error& e) {
handle_error(_("Error loading set: ") + e.what());
} catch (Error& e) {
wxMessageDialog dial = wxMessageDialog(this, _("Error loading set: ") + e.what(), _(""), wxOK|wxCENTRE|wxICON_ERROR);
dial.ShowModal();
}
}
}
@@ -140,7 +141,8 @@ void WelcomeWindow::onOpenLast(wxCommandEvent&) {
try {
close( open_package<Set>(settings.recent_sets.front()) );
} catch (PackageNotFoundError& e) {
handle_error(_("Cannot find set ") + e.what() + _(" to open."));
wxMessageDialog dial = wxMessageDialog(this, _("Cannot find set ") + e.what() + _(" to open."), _(""), wxOK|wxCENTRE|wxICON_ERROR);
dial.ShowModal();
// remove this package from the recent sets, so we don't get this error again
settings.recent_sets.erase(settings.recent_sets.begin());
}
+162 -3
View File
@@ -12,10 +12,15 @@
#include <util/delayed_index_maps.hpp>
#include <util/prec.hpp>
#include <data/card.hpp>
#include <data/card_link.hpp>
#include <data/word_list.hpp>
#include <data/statistics.hpp>
#include <data/field/information.hpp>
#include <data/field/boolean.hpp>
#include <data/field/multiple_choice.hpp>
#include <data/format/clipboard.hpp>
#include <data/update_cards_script.hpp>
#include <data/add_cards_script.hpp>
#include <render/symbol/filter.hpp>
#include <script/functions/construction_helper.hpp>
#include <sstream>
@@ -28,7 +33,7 @@
// ----------------------------------------------------------------------------- : JSON to String
void pretty_print(std::ostream& os, const boost::json::value& jv, std::string* indent)
void pretty_print(std::ostringstream& os, const boost::json::value& jv, std::string* indent)
{
std::string indent_;
if(! indent)
@@ -89,10 +94,24 @@ void pretty_print(std::ostream& os, const boost::json::value& jv, std::string* i
case boost::json::kind::uint64:
case boost::json::kind::int64:
case boost::json::kind::double_:
os << jv;
break;
case boost::json::kind::double_: {
std::ostringstream oss;
oss << std::fixed << std::setprecision(10) << jv.as_double();
std::string str = oss.str();
// remove trailing zeros
if (str.find('.') != std::string::npos) {
str.erase(str.find_last_not_of('0') + 1);
if (str.back() == '.') {
str.pop_back();
}
}
os << str;
break;
}
case boost::json::kind::bool_:
if(jv.get_bool())
os << "true";
@@ -863,15 +882,151 @@ boost::json::object mse_to_json(const Set* set) {
return setv;
}
boost::json::object mse_to_json(const StyleSheetP stylesheet) {
boost::json::object stylesheetv;
stylesheetv.emplace("mse_object_type", "stylesheet");
// built-in values
write(stylesheetv, "mse_version", stylesheet->fileVersion());
write(stylesheetv, "short_name", stylesheet->short_name);
write(stylesheetv, "full_name", stylesheet->full_name);
write(stylesheetv, "folder_name", stylesheet->folder_name + _(".mse-style"));
write(stylesheetv, "version", stylesheet->version);
write(stylesheetv, "installer_group", stylesheet->installer_group);
write(stylesheetv, "icon", stylesheet->icon_filename);
write(stylesheetv, "dark_icon", stylesheet->dark_icon_filename);
write(stylesheetv, "position_hint", stylesheet->position_hint);
write(stylesheetv, "game", stylesheet->game);
write(stylesheetv, "card_width", stylesheet->card_width);
write(stylesheetv, "card_height", stylesheet->card_height);
write(stylesheetv, "card_dpi", stylesheet->card_dpi);
write(stylesheetv, "card_background", format_color(stylesheet->card_background));
// update scripts
boost::json::array updatescriptsv;
for (const UpdateCardsScriptP& script : stylesheet->update_cards_scripts) {
updatescriptsv.emplace_back(script->before_version.toString());
}
if (!updatescriptsv.empty()) stylesheetv.emplace("update_cards_scripts", updatescriptsv);
// styling fields
boost::json::array stylingfieldsv;
for (const FieldP& field : stylesheet->styling_fields) {
stylingfieldsv.emplace_back(field->name);
}
if (!stylingfieldsv.empty()) stylesheetv.emplace("styling_fields", stylingfieldsv);
// extra fields
boost::json::array extrafieldsv;
for (const FieldP& field : stylesheet->extra_card_fields) {
extrafieldsv.emplace_back(field->name);
}
if (!extrafieldsv.empty()) stylesheetv.emplace("extra_card_fields", extrafieldsv);
// done
return stylesheetv;
}
boost::json::object mse_to_json(const Game* game) {
boost::json::object gamev;
gamev.emplace("mse_object_type", "game");
// built-in values
write(gamev, "mse_version", game->fileVersion());
write(gamev, "short_name", game->short_name);
write(gamev, "full_name", game->full_name);
write(gamev, "folder_name", game->folder_name + _(".mse-game"));
write(gamev, "version", game->version);
write(gamev, "installer_group", game->installer_group);
write(gamev, "icon", game->icon_filename);
write(gamev, "dark_icon", game->dark_icon_filename);
write(gamev, "position_hint", game->position_hint);
// update scripts
boost::json::array updatescriptsv;
for (const UpdateCardsScriptP& script : game->update_cards_scripts) {
updatescriptsv.emplace_back(script->before_version.toString());
}
if (!updatescriptsv.empty()) gamev.emplace("update_cards_scripts", updatescriptsv);
// add scripts
boost::json::array addscriptsv;
for (const AddCardsScriptP& script : game->add_cards_scripts) {
addscriptsv.emplace_back(script->name);
}
if (!addscriptsv.empty()) gamev.emplace("add_cards_scripts", addscriptsv);
// set fields
boost::json::array setfieldsv;
for (const FieldP& field : game->set_fields) {
setfieldsv.emplace_back(field->name);
}
if (!setfieldsv.empty()) gamev.emplace("set_fields", setfieldsv);
// card fields
boost::json::array cardfieldsv;
for (const FieldP& field : game->card_fields) {
cardfieldsv.emplace_back(field->name);
}
if (!cardfieldsv.empty()) gamev.emplace("card_fields", cardfieldsv);
// card links
boost::json::array cardlinksv;
for (const CardLinkP& link : game->card_links) {
cardlinksv.emplace_back(link->name());
}
if (!cardlinksv.empty()) gamev.emplace("card_links", cardlinksv);
// json paths
boost::json::array jsonpathsv;
for (const String& path : game->json_paths) {
jsonpathsv.emplace_back(path);
}
if (!jsonpathsv.empty()) gamev.emplace("json_paths", jsonpathsv);
// word lists
boost::json::array wordlistsv;
for (const WordListP& list : game->word_lists) {
wordlistsv.emplace_back(list->name);
}
if (!wordlistsv.empty()) gamev.emplace("word_lists", wordlistsv);
// keywords
boost::json::array keywordmodesv;
for (const KeywordModeP& mode : game->keyword_modes) {
keywordmodesv.emplace_back(mode->name);
}
if (!keywordmodesv.empty()) gamev.emplace("keyword_modes", keywordmodesv);
boost::json::array keywordparametersv;
for (const KeywordParamP& mode : game->keyword_parameter_types) {
keywordparametersv.emplace_back(mode->name);
}
if (!keywordparametersv.empty()) gamev.emplace("keyword_parameters", keywordparametersv);
boost::json::array keywordsv;
for (const KeywordP& keyword : game->keywords) {
keywordsv.emplace_back(keyword->keyword);
}
if (!keywordsv.empty()) gamev.emplace("keywords", keywordsv);
// pack types
boost::json::array pack_typesv;
for (const PackTypeP& pack_type : game->pack_types) {
pack_typesv.emplace_back(pack_type->name);
}
if (!pack_typesv.empty()) gamev.emplace("pack_types", pack_typesv);
// statistics
boost::json::array statisticsdimensionsv;
for (const StatsDimensionP& stat : game->statistics_dimensions) {
statisticsdimensionsv.emplace_back(stat->name);
}
if (!statisticsdimensionsv.empty()) gamev.emplace("statistics_dimensions", statisticsdimensionsv);
// done
return gamev;
}
boost::json::object mse_to_json(const IndexMap<FieldP, ValueP>& map) {
boost::json::object indexmapv;
indexmapv.emplace("mse_object_type", "index_map");
indexmapv.emplace("mse_object_type", "value_index_map");
for (auto it = map.begin(); it != map.end(); ++it) {
write(indexmapv, (*it)->fieldP->name, *it);
}
return indexmapv;
}
boost::json::object mse_to_json(const IndexMap<FieldP, StyleP>& map) {
boost::json::object indexmapv;
indexmapv.emplace("mse_object_type", "style_index_map");
for (auto it = map.begin(); it != map.end(); ++it) {
indexmapv.emplace((*it)->fieldP->name.ToStdString(), mse_to_json(*it));
}
return indexmapv;
}
boost::json::value mse_to_json(const ScriptValueP& sv, Set* set, bool suppress_warnings) {
// special types
if (ScriptObject<PackItemP>* o = dynamic_cast<ScriptObject<PackItemP>*> (sv.get())) return mse_to_json( o->getValue());
@@ -881,7 +1036,11 @@ boost::json::value mse_to_json(const ScriptValueP& sv, Set* set, bool suppress_w
if (ScriptObject<CardP>* o = dynamic_cast<ScriptObject<CardP>*> (sv.get())) return mse_to_json( o->getValue(), set);
if (ScriptObject<SetP>* o = dynamic_cast<ScriptObject<SetP>*> (sv.get())) return mse_to_json( o->getValue().get());
if (ScriptObject<Set*>* o = dynamic_cast<ScriptObject<Set*>*> (sv.get())) return mse_to_json( o->getValue());
if (ScriptObject<StyleSheetP>* o = dynamic_cast<ScriptObject<StyleSheetP>*> (sv.get())) return mse_to_json( o->getValue());
if (ScriptObject<GameP>* o = dynamic_cast<ScriptObject<GameP>*> (sv.get())) return mse_to_json( o->getValue().get());
if (ScriptObject<Game*>* o = dynamic_cast<ScriptObject<Game*>*> (sv.get())) return mse_to_json( o->getValue());
if (ScriptMap<IndexMap<FieldP,ValueP>>* o = dynamic_cast<ScriptMap<IndexMap<FieldP,ValueP>>*>(sv.get())) return mse_to_json(*o->value);
if (ScriptMap<IndexMap<FieldP,StyleP>>* o = dynamic_cast<ScriptMap<IndexMap<FieldP,StyleP>>*>(sv.get())) return mse_to_json(*o->value);
// primitive types
ScriptType type = sv->type();
+6
View File
@@ -68,8 +68,14 @@ boost::json::object mse_to_json(const StyleP& style);
boost::json::object mse_to_json(const CardP& card, const Set* set);
boost::json::object mse_to_json(const StyleSheetP set);
boost::json::object mse_to_json(const Set* set);
boost::json::object mse_to_json(const Game* set);
boost::json::object mse_to_json(const IndexMap<FieldP,ValueP>& map);
boost::json::object mse_to_json(const IndexMap<FieldP,StyleP>& map);
boost::json::value mse_to_json(const ScriptValueP& sv, Set* set, bool suppress_warnings = false);
+2 -3
View File
@@ -49,9 +49,8 @@ bool ScriptableImage::update(Context& ctx) {
value = new_value;
ScriptType type = eval->type();
if (type == SCRIPT_NIL) scriptString = _("<nil>");
else if (type == SCRIPT_STRING) scriptString = eval->toString();
else if (type == SCRIPT_IMAGE) scriptString = _("<image from script>");
else scriptString = _("<unknown>");
else if (type == SCRIPT_STRING) { String string = eval->toString(); if (string.empty()) scriptString = _("<nil>"); else scriptString = string; }
else if (type == SCRIPT_IMAGE) scriptString = _("<image from script>");
return true;
} else {
return false;
+13 -1
View File
@@ -45,7 +45,19 @@ public:
bool update(Context& ctx);
/// Get the string (filename) produced by the script, for debugging
inline String toScriptString() { return scriptString; }
inline String toScriptString() {
if (!scriptString.empty()) return scriptString;
const String& unparsed = script.getUnparsed();
if (starts_with(unparsed, _("script:"))) {
if (trim(unparsed.substr(7)) == _("\"\"")) return _("<nil>");
else return _("<image from script>");
}
if (starts_with(unparsed, _("{"))) {
if (trim(unparsed.substr(1, unparsed.length()-2)) == _("\"\"")) return _("<nil>");
else return _("<image from script>");
}
return unparsed;
}
inline void initDependencies(Context& ctx, const Dependency& dep) const {
script.initDependencies(ctx, dep);
+4 -3
View File
@@ -226,8 +226,9 @@ unique_ptr<wxInputStream> Package::openIn(const String& file) {
}
FileInfos::iterator it = files.find(normalize_internal_filename(file));
if (it == files.end()) {
// does it look like a relative filename?
if (size_t pos = filename.find(_(".mse-")) != String::npos) {
// does it look like a relative filename?
size_t pos = filename.find(_(".mse-"));
if (pos != String::npos) {
// check for nested folder
pos = filename.find_last_of(_("/\\"));
String nestedFilename = filename + filename.SubString(pos, filename.size()) + wxFileName::GetPathSeparator() + file;
@@ -235,7 +236,7 @@ unique_ptr<wxInputStream> Package::openIn(const String& file) {
throw PackageError(_ERROR_1_("nested folder", filename));
}
else {
throw PackageError(_ERROR_2_("file not found package like", file, filename));
throw PackageNotFoundError(_ERROR_2_("file not found package like", file, filename));
}
}
}
+68 -19
View File
@@ -19,6 +19,7 @@
#include <data/installer.hpp>
#include <wx/stdpaths.h>
#include <wx/wfstream.h>
#include <wx/dir.h>
// ----------------------------------------------------------------------------- : PackageManager : in memory
@@ -31,21 +32,31 @@ void PackageManager::init() {
if (!(local.valid() || global.valid()))
throw Error(_("The MSE data files can not be found, there should be a directory called 'data' with these files. ")
_("The expected place to find it in was either ") + wxStandardPaths::Get().GetDataDir() + _(" or ") +
wxStandardPaths::Get().GetUserDataDir());
wxStandardPaths::Get().GetUserDataDir());
local.deleteEmptyFolders();
global.deleteEmptyFolders();
}
void PackageManager::destroy() {
loaded_packages.clear();
}
void PackageManager::reset() {
loaded_packages.clear();
}
}
PackagedP PackageManager::openAny(const String& name_, bool just_header) {
void PackageManager::evictFromCache(const String& name_) {
String filename = normalizeFilename(cleanFilename(name_));
loaded_packages.erase(filename);
}
String PackageManager::cleanFilename(const String& name_) {
String name = trim(name_);
if (starts_with(name,_("/"))) name = name.substr(1);
if (starts_with(name,_(":NO-WARN-DEP:"))) name = name.substr(13);
// Attempt to load local data first.
if (starts_with(name,_(":NO-WARN-DEP:"))) name = name.substr(13);
return name;
}
String PackageManager::normalizeFilename(const String& name) {
String filename;
// Attempt to load local data first.
if (wxFileName(name).IsRelative()) {
// local data dir?
filename = normalize_filename(local.name(name));
@@ -55,8 +66,13 @@ PackagedP PackageManager::openAny(const String& name_, bool just_header) {
}
} else { // Absolute filename
filename = normalize_filename(name);
}
}
return filename;
}
PackagedP PackageManager::openAny(const String& name_, bool just_header) {
String name = cleanFilename(name_);
String filename = normalizeFilename(name);
// Is this package already loaded?
PackagedP& p = loaded_packages[filename];
if (!p) {
@@ -84,20 +100,24 @@ PackagedP PackageManager::openAny(const String& name_, bool just_header) {
void PackageManager::findMatching(const String& pattern, vector<PackagedP>& out) {
// first find local packages
String file = local.findFirstMatching(pattern);
while (!file.empty()) {
out.push_back(openAny(file, true));
while (!file.empty()) {
if (local.checkForPackageFile(file)) {
out.push_back(openAny(file, true));
}
file = wxFindNextFile();
}
// then global packages not already in the list
file = global.findFirstMatching(pattern);
while (!file.empty()) {
PackagedP p = openAny(file, true);
if (find(out.begin(), out.end(), p) == out.end()) {
out.push_back(p);
while (!file.empty()) {
if (global.checkForPackageFile(file)) {
PackagedP p = openAny(file, true);
if (find(out.begin(), out.end(), p) == out.end()) {
out.push_back(p);
}
}
file = wxFindNextFile();
}
}
}
bool PackageManager::existsInPackage(const String& name) {
if (!name.empty() && name.GetChar(0) == _('/')) {
@@ -213,7 +233,7 @@ void PackageManager::findAllInstalledPackages(vector<InstallablePackageP>& packa
bool PackageManager::install(const InstallablePackage& package) {
bool install_local = package.has(PACKAGE_ACT_LOCAL);
return (install_local ? local : global).install(package);
}
}
// ----------------------------------------------------------------------------- : PackageDirectory
@@ -245,11 +265,22 @@ void PackageDirectory::init(const String& dir) {
directory = dir;
else
directory.clear();
}
}
void PackageDirectory::deleteEmptyFolders() {
for (String file = findFirstMatching(_("*.mse-*")) ; !file.empty() ; file = wxFindNextFile()) {
if (!wxDir::Exists(file)) continue;
wxDir outerDir(file);
if (!outerDir.HasFiles() && !outerDir.HasSubDirs()) {
wxRmdir(file);
}
}
}
String PackageDirectory::name(const String& name) const {
return directory + _("/") + name;
}
}
bool PackageDirectory::exists(const String& filename) const {
String fn = name(filename);
return wxFileExists(fn) || wxDirExists(fn);
@@ -263,6 +294,21 @@ String PackageDirectory::findFirstMatching(const String& pattern) const {
bool compare_name(const PackageVersionP& a, const PackageVersionP& b) {
return a->name < b->name;
}
bool PackageDirectory::checkForPackageFile(const String& folder_name) {
size_t package_pos = folder_name.find_last_of(_("."));
if (package_pos == String::npos) {
queue_message(MESSAGE_WARNING, _ERROR_1_("package name parse error", folder_name));
return false;
}
String package_name = folder_name.substr(package_pos+5);
String package_file = folder_name + wxFileName::GetPathSeparator() + package_name;
if (!wxFileExists(package_file) && !wxFileExists(directory + wxFileName::GetPathSeparator() + package_file)) {
queue_message(MESSAGE_WARNING, _ERROR_2_("file not found package like init", package_name, folder_name));
return false;
}
return true;
}
void PackageDirectory::installedPackages(vector<InstallablePackageP>& packages_out) {
loadDatabase();
@@ -270,9 +316,11 @@ void PackageDirectory::installedPackages(vector<InstallablePackageP>& packages_o
vector<String> in_dir;
for (String s = findFirstMatching(_("*.mse-*")) ; !s.empty() ; s = wxFindNextFile()) {
size_t pos = s.find_last_of(_("/\\"));
if (pos != String::npos) s = s.substr(pos+1);
if (pos != String::npos) s = s.substr(pos+1);
// TODO : check for valid package names
in_dir.push_back(s);
if (checkForPackageFile(s)) {
in_dir.push_back(s);
}
}
sort(in_dir.begin(), in_dir.end());
// merge with package database
@@ -387,7 +435,8 @@ bool PackageDirectory::install(const InstallablePackage& package) {
if (!rename_file_or_dir(n + _(".new"), n)) return false;
bless(package.description->name);
}
saveDatabase();
saveDatabase();
package_manager.evictFromCache(package.description->name);
return true;
}
+19 -8
View File
@@ -60,8 +60,10 @@ IMPLEMENT_REFLECTION_NO_SCRIPT(UpdateData) {
class PackageDirectory {
public:
void init(bool local);
void init(const String& dir);
void init(const String& dir);
void deleteEmptyFolders();
bool valid() const { return !directory.empty(); }
/// Name of a package in this directory
@@ -74,7 +76,10 @@ public:
/// Find all packages that match a filename pattern (using wxFindFirst)
String findFirstMatching(const String& pattern) const;
/// Verify that a package contains its titular file
bool checkForPackageFile(const String& package_name);
/// Get all installed packages
void installedPackages(vector<InstallablePackageP>& packages);
@@ -115,8 +120,10 @@ public:
* we could get into fights with pool allocators used by ScriptValues */
void destroy();
/// Empty the list of packages, they will all be reloaded
void reset();
void reset();
/// Clear a package from the list, it will be reloaded
void evictFromCache(const String& filename_or_name);
// --------------------------------------------------- : Packages in memory
/// Open a package with the specified name (including extension)
@@ -130,7 +137,11 @@ public:
throw InternalError(format_string(_("Package %s loaded as wrong type"),name));
}
}
/// Prepare a filename so that it can be used as a key in loaded_packages
String cleanFilename(const String& name);
String normalizeFilename(const String& name);
/// Open a package with the specified name, the type of package is determined by its extension!
/** @param if just_header is true, then the package is not fully parsed.
*/
@@ -170,8 +181,8 @@ public:
void findAllInstalledPackages(vector<InstallablePackageP>& packages);
/// Install/uninstall a package, returns success
bool install(const InstallablePackage& package);
bool install(const InstallablePackage& package);
// --------------------------------------------------- : Other package like things
/// Get the directory for dictionary files
+1 -1
View File
@@ -280,7 +280,7 @@ void RotatedDC::DrawRoundedRectangle(const RealRect& r, double radius) {
void RotatedDC::DrawInvertRectangle(const RealRect& r) {
wxRect r_ext = trRectToBB(r);
wxBitmap bmp(r_ext.width, r_ext.height, 24);
wxBitmap bmp(r_ext.width, r_ext.height, 24);
wxMemoryDC memDC(bmp);
memDC.Blit(0, 0, r_ext.width, r_ext.height, &dc, r_ext.x, r_ext.y);
memDC.SelectObject(wxNullBitmap);
+5 -5
View File
@@ -91,12 +91,12 @@ const Char* version_suffix = _(" (ascii build)");
* 2.0.2 : store game and stylesheet version numbers
*/
const Version file_version_locale = Version(2u, 0u, 2u);
const Version file_version_set = Version(2u, 0u, 2u);
const Version file_version_game = Version(0u, 3u, 8u);
const Version file_version_stylesheet = Version(0u, 3u, 8u);
const Version file_version_set = Version(2u, 6u, 0u);
const Version file_version_game = Version(2u, 6u, 0u);
const Version file_version_stylesheet = Version(2u, 6u, 0u);
const Version file_version_symbol_font = Version(0u, 3u, 6u);
const Version file_version_export_template = Version(0u, 3u, 7u);
const Version file_version_installer = Version(0u, 3u, 7u);
const Version file_version_installer = Version(2u, 6u, 0u);
const Version file_version_symbol = Version(0u, 3u, 5u);
const Version file_version_clipboard = Version(2u, 6u, 0u);
const Version file_version_script = Version(0u, 3u, 7u);
const Version file_version_script = Version(2u, 6u, 0u);
+9 -2
View File
@@ -335,6 +335,13 @@ enum ControlID {
ID_CARD_LINK_RELATION_1,
ID_CARD_LINK_RELATION_2,
ID_CARD_LINK_RELATION_3,
ID_CARD_LINK_RELATION_4,
};
ID_CARD_LINK_RELATION_4,
// Select stylesheet window
ID_DOWNLOAD_STYLESHEET,
};
// ----------------------------------------------------------------------------- : Custom Events
DECLARE_EVENT_TYPE(EVENT_PACKAGE_LIST_CHANGED, <not used>);