1 Commits

Author SHA1 Message Date
Amy Markey 2f83850b60 Developer list addition
Adding myself to the developer list for vanity purposes.
2026-04-19 07:36:08 -04:00
101 changed files with 996 additions and 2916 deletions
+1 -15
View File
@@ -54,8 +54,6 @@ menu:
next card: 选择下一张卡牌 PgDn
search cards: 搜索卡 Ctrl+K
add card: 添加卡牌 Ctrl+Enter
#TODO: Localize
add card double: &Add Double Faced Card Ctrl+Shift+Enter
add cards: 批量添加卡牌...
remove card: 删除所选卡牌
#TODO: Localize
@@ -210,8 +208,6 @@ help:
next card: 选择列表中的下一张卡牌
search cards: 使用搜索词过滤卡片列表
add card: 添加一个新的空白卡牌到本套牌
#TODO: Localize
add card double: Add a new, blank, card that has a back face to this set
add cards: 添加多张卡牌到本套牌
remove card: 从本套牌中删除所选卡牌
#TODO: Localize
@@ -472,8 +468,6 @@ tooltip:
# cards toolbar
add card: 添加卡牌
#TODO: Localize
add card double: Add double faced card
remove card: 移除选中卡牌
#TODO: Localize
link card: Link cards to selected card
@@ -764,8 +758,6 @@ label:
installable version: 最新版本
installer size: 尺寸
installer status: 地位
#TODO: Localize
folder name: Folder name:
no version: -
#TODO: Localize
@@ -898,8 +890,6 @@ button:
upgrade package: 升级
reinstall package: 重新安装
remove package: 移除
#TODO: Localize
keep group: Keep Group As Is
install group: 全部安装
upgrade group: 全部升级
remove group: 全部移除
@@ -991,8 +981,6 @@ action:
# cards
#TODO: Localize Section
reorder cards: Reorder cards
#TODO: Localize
update card: Update card
change link: Change link
change notes: Change notes
change id: Change ID
@@ -1142,9 +1130,7 @@ error:
# image stuff
coordinates for blending overlap: 坐标混合重叠
#TODO: Localize
blending different sizes: Images used for blending must have the same size in function '%s' (one is %s, the other is %s)
#TODO: Localize
blending different mask: Image and mask used for blending must have the same size in function '%s' (image is %s, mask is %s)
blending different sizes: Images used for blending must have the same size in function '%s'
#TODO: Localize
negative image width: Image with zero or negative width created in function '%s'
#TODO: Localize
+1 -15
View File
@@ -54,8 +54,6 @@ menu:
next card: 選擇下一張卡牌 PgDn
search cards: 搜尋卡 Ctrl+K
add card: 添加卡牌 Ctrl+Enter
#TODO: Localize
add card double: &Add Double Faced Card Ctrl+Shift+Enter
add cards: 批量添加卡牌...
remove card: 刪除所選卡牌
#TODO: Localize
@@ -210,8 +208,6 @@ help:
next card: 選擇列表中的下一張卡牌
search cards: 使用搜尋字詞過濾卡片列表
add card: 添加一個新的空白卡牌到本套牌
#TODO: Localize
add card double: Add a new, blank, card that has a back face to this set
add cards: 添加多張卡牌到本套牌
remove card: 從本套牌中刪除所選卡牌
#TODO: Localize
@@ -470,8 +466,6 @@ tooltip:
# cards toolbar
add card: 添加卡牌
#TODO: Localize
add card double: Add double faced card
remove card: 移除選中卡牌
#TODO: Localize
link card: Link cards to selected card
@@ -762,8 +756,6 @@ label:
installable version: 最新版本
installer size: 尺寸
installer status: 地位
#TODO: Localize
folder name: Folder name:
no version: -
#TODO: Localize
@@ -896,8 +888,6 @@ button:
upgrade package: 昇級
reinstall package: 重新安裝
remove package: 移除
#TODO: Localize
keep group: Keep Group As Is
install group: 全部安裝
upgrade group: 全部昇級
remove group: 全部移除
@@ -989,8 +979,6 @@ action:
# cards
#TODO: Localize Section
reorder cards: Reorder cards
#TODO: Localize
update card: Update card
change link: Change link
change notes: Change notes
change id: Change ID
@@ -1140,9 +1128,7 @@ error:
# image stuff
coordinates for blending overlap: 坐標混合重疊
#TODO: Localize
blending different sizes: Images used for blending must have the same size in function '%s' (one is %s, the other is %s)
#TODO: Localize
blending different mask: Image and mask used for blending must have the same size in function '%s' (image is %s, mask is %s)
blending different sizes: Images used for blending must have the same size in function '%s'
#TODO: Localize
negative image width: Image with zero or negative width created in function '%s'
#TODO: Localize
+1 -15
View File
@@ -56,8 +56,6 @@ menu:
next card: Vælg &Næste Kort PgDn
search cards: &Søg kort Ctrl+K
add card: &Tilføj Kort Ctrl+Enter
#TODO: Localize
add card double: &Add Double Faced Card Ctrl+Shift+Enter
add cards: Tilføj &Flere Kort...
remove card: &Slet Valgte Kort
#TODO: Localize
@@ -216,8 +214,6 @@ help:
next card: Vælger det næste kort i listen
search cards: Filtrer kortlisten ved hjælp af søgetermer
add card: Tilføler et nyt, tomt kort til listen
#TODO: Localize
add card double: Add a new, blank, card that has a back face to this set
add cards: Tilføjer flere kort til listen
remove card: Sletter det valgte kort fra sættet!
#TODO: Localize
@@ -481,8 +477,6 @@ tooltip:
# cards toolbar
add card: Tilføj kort
#TODO: Localize
add card double: Add double faced card
remove card: Fjern valgte kort
#TODO: Localize
link card: Link cards to selected card
@@ -780,8 +774,6 @@ label:
installable version: seneste version:
installer size: Størrelse:
installer status: Status:
#TODO: Localize
folder name: Folder name:
no version: -
#TODO: Localize
@@ -914,8 +906,6 @@ button:
upgrade package: &Opdatér
reinstall package: Gen&installér
remove package: &Fjern
#TODO: Localize
keep group: Keep Group As Is
install group: &Installér Alt
upgrade group: &Opgradér Alt
remove group: &Fjern Alt
@@ -1009,8 +999,6 @@ action:
# cards
#TODO: Localize Section
reorder cards: Reorder cards
#TODO: Localize
update card: Update card
change link: Change link
change notes: Change notes
change id: Change ID
@@ -1166,9 +1154,7 @@ error:
#TODO: Localize
coordinates for blending overlap: Coordinates for blending overlap. Space them out.
#TODO: Localize
blending different sizes: Images used for blending must have the same size in function '%s' (one is %s, the other is %s)
#TODO: Localize
blending different mask: Image and mask used for blending must have the same size in function '%s' (image is %s, mask is %s)
blending different sizes: Images used for blending must have the same size in function '%s'
#TODO: Localize
negative image width: Image with zero or negative width created in function '%s'
#TODO: Localize
+7 -14
View File
@@ -54,7 +54,6 @@ menu:
next card: Nächste Karte PgDn
search cards: Suchkarten Ctrl+K
add card: Karte Hinzufügen Ctrl+Enter
add card double: Doppelseitige Karte hinzufügen Ctrl+Shift+Enter
add cards: Mehrere Karten hinzufügen...
remove card: Markierte Entfernen Del
add card csv: Karten aus CSV oder TSV hinzufügen...
@@ -196,8 +195,7 @@ help:
previous card: Wählt die vorherige Karte in der Liste aus
next card: Wählt die nächste Karte in der Liste aus
search cards: Filtert die Kartenliste anhand von Suchbegriffen
add card: Fügt eine neue, leere Karte zur Edition hinzu
add card double: Fügt eine neue, leere Karte mit Rückseite zur Edition hinzu
add card: Fügt eine neue Karte zur Edition hinzu
add cards: Fügt mehrere Karten zur Edition hinzu
remove card: Entfernt die gewählte Karte aus der Edition
link card: Verknüpft eine oder mehrere Karten mit der ausgewählten Karte
@@ -444,7 +442,6 @@ tooltip:
# cards toolbar
add card: Karte hinzufügen
add card double: Doppelseitige Karte hinzufügen
remove card: Gewählte Karte entfernen
link card: Karten mit ausgewählter Karte verknüpfen
copy card and links: Ausgewählte und verknüpfte Karten kopieren
@@ -712,7 +709,6 @@ label:
installable version: Letzte Version
installer size: Größe
installer status: Status:
folder name: Ordnername:
no version: -
load image: Doppelklicken Sie, um ein Bild zu laden
@@ -825,16 +821,15 @@ button:
close: &Beenden
# packages window
keep package: &Unverändert beibehalten
keep package: &Nicht verändern
don't install package: &Nicht installieren
install package: &Installieren
upgrade package: &Aktualisieren
upgrade package: &Upgraden
reinstall package: Neu &installieren
remove package: &Entfernen
keep group: Gruppe unverändert beibehalten
install group: Gruppe installieren/aktualisieren
upgrade group: Gruppe aktualisieren
remove group: Gruppe entfernen
install group: &Installiere alle
upgrade group: &Upgrade alle
remove group: &Entferne alle
############################################################## Titles in the GUI
title:
@@ -914,7 +909,6 @@ title:
action:
# cards
reorder cards: Karten neu anordnen
update card: Karte aktualisieren
change link: Link ändern
change notes: Notizen ändern
change id: ID ändern
@@ -1053,8 +1047,7 @@ error:
# image stuff
coordinates for blending overlap: Die Koordinaten für die Überblendung überlappen sich.
blending different sizes: Die für die Überblendung verwendeten Bilder müssen in der Funktion '%s' die gleiche Größe haben. (Eines ist %s, das andere ist %s)
blending different mask: Bild und Maske, die zum Überblenden verwendet werden, müssen in der Funktion '%s' die gleiche Größe haben. (Bild ist %s, Maske ist %s)
blending different sizes: Die für die Überblendung verwendeten Bilder müssen in der Funktion '%s' die gleiche Größe haben.
negative image width: Bild mit Breite Null oder negativer Breite, erstellt in der Funktion '%s'
negative image height: Bild mit Höhe Null oder negativer Höhe, erstellt in der Funktion '%s'
can't load image: Bild konnte nicht geladen werden. Stelle sicher, dass das tatsächliche Format des Bildes mit der gespeicherten Dateiendung übereinstimmt.
+6 -13
View File
@@ -54,7 +54,6 @@ menu:
next card: Select &Next Card PgDn
search cards: &Search Cards Ctrl+K
add card: &Add Card Ctrl+Enter
add card double: &Add Double Faced Card Ctrl+Shift+Enter
add cards: Add &Multiple Cards...
remove card: &Delete Selected Card
add card csv: Add Cards from CSV or TSV...
@@ -197,7 +196,6 @@ help:
next card: Selects the next card in the list
search cards: Filter the card list using search terms
add card: Add a new, blank, card to this set
add card double: Add a new, blank, card that has a back face to this set
add cards: Add multiple cards to the set
remove card: Delete the selected card from this set
link card: Link one or more cards to the selected card
@@ -445,7 +443,6 @@ tooltip:
# cards toolbar
add card: Add card
add card double: Add double faced card
remove card: Remove selected card
link card: Link cards to selected card
copy card and links: Copy selected cards and linked cards
@@ -711,7 +708,6 @@ label:
installable version: Latest version:
installer size: Size:
installer status: Status:
folder name: Folder name:
no version: -
load image: Double click to load image
@@ -826,16 +822,15 @@ button:
close: &Close
# packages window
keep package: Keep As Is
don't install package: &Don't Install
keep package: &Don't change
don't install package: &Don't install
install package: &Install
upgrade package: &Update
reinstall package: Re&install
remove package: &Remove
keep group: Keep Group As Is
install group: &Install/Update Group
upgrade group: &Update Group
remove group: &Remove Group
install group: &Install All
upgrade group: &Upgrade All
remove group: &Remove All
############################################################## Titles in the GUI
title:
@@ -915,7 +910,6 @@ title:
action:
# cards
reorder cards: Reorder cards
update card: Update card
change link: Change link
change notes: Change notes
change id: Change ID
@@ -1054,8 +1048,7 @@ error:
# image stuff
coordinates for blending overlap: Coordinates for blending overlap. Space them out.
blending different sizes: Images used for blending must have the same size in function '%s' (one is %s, the other is %s)
blending different mask: Image and mask used for blending must have the same size in function '%s' (image is %s, mask is %s)
blending different sizes: Images used for blending must have the same size in function '%s'
negative image width: Image with zero or negative width created in function '%s'
negative image height: Image with zero or negative height created in function '%s'
can't load image: Failed to load image. Ensure the image's actual format matches its saved extension.
+1 -15
View File
@@ -54,8 +54,6 @@ menu:
next card: Seleccionar &carta siguiente PgDn
search cards: &Buscar Cartas Ctrl+K
add card: &Añadir carta Ctrl+Enter
#TODO: Localize
add card double: &Add Double Faced Card Ctrl+Shift+Enter
add cards: Añadir &múltiples cartas...
remove card: &Borrar carta seleccionada
#TODO: Localize
@@ -210,8 +208,6 @@ help:
next card: Selecciona la carta siguiente en la lista
search cards: Filtra la lista de cartas usando términos de búsqueda
add card: Añade una carta nueva, vacía, a este Set
#TODO: Localize
add card double: Add a new, blank, card that has a back face to this set
add cards: Añade múltiples cartas al Set
remove card: Borra la carta seleccionada de este Set
#TODO: Localize
@@ -472,8 +468,6 @@ tooltip:
# cards toolbar
add card: Añadir carta
#TODO: Localize
add card double: Add double faced card
remove card: Eliminar carta seleccionada
#TODO: Localize
link card: Link cards to selected card
@@ -765,8 +759,6 @@ label:
installable version: Última versión:
installer size: Tamaño:
installer status: Estado:
#TODO: Localize
folder name: Folder name:
no version: -
#TODO: Localize
@@ -899,8 +891,6 @@ button:
upgrade package: &Actualizar
reinstall package: R&einstalar
remove package: &Eliminar
#TODO: Localize
keep group: Keep Group As Is
install group: Instalar &Todos
upgrade group: A&ctualizar Todos
remove group: Q&uitar Todos
@@ -992,8 +982,6 @@ action:
# cards
#TODO: Localize Section
reorder cards: Reorder cards
#TODO: Localize
update card: Update card
change link: Change link
change notes: Change notes
change id: Change ID
@@ -1143,9 +1131,7 @@ error:
# image stuff
coordinates for blending overlap: Coordenadas para la mezcla (blending) solapada
#TODO: Localize
blending different sizes: Images used for blending must have the same size in function '%s' (one is %s, the other is %s)
#TODO: Localize
blending different mask: Image and mask used for blending must have the same size in function '%s' (image is %s, mask is %s)
blending different sizes: Images used for blending must have the same size in function '%s'
#TODO: Localize
negative image width: Image with zero or negative width created in function '%s'
#TODO: Localize
+92 -99
View File
@@ -54,9 +54,8 @@ menu:
next card: Carte &Suivante PgDn
search cards: Rechercher dans les Cartes Ctrl+K
add card: &Ajouter une Carte Ctrl+Enter
add card double: Ajouter une Carte recto-verso Ctrl+Shift+Enter
add cards: Ajouter &plusieurs Cartes...
remove card: &Supprimer la Carte sélectionnée
remove card: &Supprimer la carte sélectionnée
add card csv: Ajouter plusieurs Cartes depuis un CSV ou TSV...
add card json: Ajouter plusieurs Cartes depuis un JSON...
link card: &Lier des Cartes à la Carte sélectionnée...
@@ -160,15 +159,15 @@ help:
save set as directory: Sauver le Set en tant que dossier non compressé
export: Exporter le Set...
export html: Exporter le Set en tant que fichier HTML
export image: Exporter la Carte selectionnée en tant qu'image
export images: Exporter toutes les Cartes en tant qu'images
export image: Exporter la carte selectionnée en tant qu'image
export images: Exporter toutes les cartes en tant qu'images
export apprentice: Exporter le Set pour être utilisé avec Apprentice
export mws: Exporter le Set pour être utilisé avec Magic Workstation
add card csv: Ajouter des Cartes depuis un fichier à Valeurs Séparées par des Virgules ou Tabulations
add card json: Ajouter des Cartes depuis un fichier JSON
check updates: Ouvrir une fenêtre de mise à jour pour télécharger les nouveaux packages (Jeux, Styles, Localisations)
print preview: Voir les Cartes telles qu'elles vont être imprimées
print: Imprimer les Cartes de ce Set
print preview: Voir les cartes telles qu'elles vont être imprimées
print: Imprimer les cartes de ce Set
reload data: Recharger tous les Templates ainsi que le Set
show profiler: Afficher la fenêtre du Profiler, avec la durée d'exécution des scripts; Utilisé pour l'optimisation
exit: Quitter Magic Set Editor; Vous demandera de sauvegarder le Set
@@ -177,38 +176,37 @@ help:
undo: Annuler la dernière action
redo: Refaire la dernière action
cut: Couper le texte selectionné dans le presse-papier
cut card: Couper la Carte selectionnée dans le presse-papier
cut card: Couper la carte selectionnée dans le presse-papier
cut keyword: Couper le Mot-clef selectionné dans le presse-papier
copy: Copier le texte selectionné dans le presse-papier
copy card: Copier la Carte selectionnée dans le presse-papier
copy card: Copier la carte selectionnée dans le presse-papier
copy keyword: Copier le Mot-clef selectionné dans le presse-papier
paste: Insérer le texte depuis le presse-papier
paste card: Insérer la Carte depuis le presse-papier
paste card: Insérer la carte depuis le presse-papier
paste keyword: Insérer le mot_clef depuis le presse-papier
select all: Sélectionner tout le texte
find: Rechercher un bout de texte dans les Cartes
find: Rechercher un bout de texte dans les cartes
find next: Rechercher l'occurrence suivante
replace: Remplacer l'occurrence
auto replace: Quel texte devra être automatiquement remplacé?
preferences: Changer la configuration de Magic Set Editor
# cards menu
previous card: Choisir la Carte précédente dans la liste
next card: Choisir la Carte suivante dans la liste
search cards: Filtrer la liste des Carte à l'aide de termes de recherche
add card: Ajouter une nouvelle Carte vierge au Set
add card double: Ajouter une nouvelle Carte vierge avec un verso au Set
add cards: Ajouter plusieurs Cartes au Set
remove card: Supprimer la Carte sélectionnée du Set
link card: Lier des Cartes à la Carte sélectionnée
copy card and links: Copier les Cartes sélectionnées ainsi que toutes leurs Cartes liées
bulk modify: Modifier beaucoup de Cartes d'un coup
orientation: Orientation de la Carte visualisée
rotate card: Tourner la Carte de 90° dans le sens des aiguilles d'une montre
rotate 0: Afficher la Carte dans son sens original
rotate 270: Afficher la Carte tournée dans le sens des aiguilles d'une montre
rotate 90: Afficher la Carte tournée dans le sens inverse des aiguilles d'une montre
rotate 180: Afficher la Carte à l'envers
previous card: Choisir la carte précédente dans la liste
next card: Choisir la carte suivante dans la liste
search cards: Filtrer la liste des carte à l'aide de termes de recherche
add card: Ajouter une nouvelle carte vierge au Set
add cards: Ajouter plusieurs cartes au Set
remove card: Supprimer la carte sélectionnée du Set
link card: Lier des cartes à la carte sélectionnée
copy card and links: Copier les cartes sélectionnées ainsi que toutes leurs cartes liées
bulk modify: Modifier beaucoup de cartes d'un coup
orientation: Orientation de la carte visualisée
rotate card: Tourner la carte de 90° dans le sens des aiguilles d'une montre
rotate 0: Afficher la carte dans son sens original
rotate 270: Afficher la carte tournée dans le sens des aiguilles d'une montre
rotate 90: Afficher la carte tournée dans le sens inverse des aiguilles d'une montre
rotate 180: Afficher la carte à l'envers
card list columns: Choisir quelles colonnes doivent être affichées et dans quel ordre
# keywords menu
@@ -233,10 +231,10 @@ help:
no spelling suggestions: Il n'y a pas de suggestions pour corriger cette faute
# graph menu
pie: Un graphique en secteurs, l'épaisseur de la tranche indique le nombre de Cartes
bar: Un graphique à barres, la hauteur de la barre indique le nombre de Cartes
pie: Un graphique en secteurs, l'épaisseur de la tranche indique le nombre de cartes
bar: Un graphique à barres, la hauteur de la barre indique le nombre de cartes
stack: Un graphique à barres empilées
scatter: Un nuage de points, la taille du point indique le nombre de Cartes
scatter: Un nuage de points, la taille du point indique le nombre de cartes
scatter pie: Un nuage de points où chaque point est un petit graphique en secteurs
# console menu
@@ -244,12 +242,12 @@ help:
# window menu
new window: Ouvrir une nouvelle fenêtre pour éditer le même Set
cards tab: Éditer les Cartes du Set
cards tab: Éditer les cartes du Set
set info tab: Éditer les informations du Set, son créateur, etc...
style tab: Changer le Style des Cartes
style tab: Changer le Style des cartes
keywords tab: Définir des Mots-clefs supplémentaires pour le Set
stats tab: Voir les statistiques des Cartes du Set
random pack tab: Générer des boosters aléatoires de Cartes du Set
stats tab: Voir les statistiques des cartes du Set
random pack tab: Générer des boosters aléatoires de cartes du Set
console tab: Afficher les messages d'erreurs et executer des scripts
# help menu
@@ -263,12 +261,12 @@ help:
search stylesheet list control: Filtrer la liste des Styles. Utilisez - pour exclure des Styles. Utilisez field: pour rechercher uniquement dans un champ donné. Utilisez des guillemets pour une recherche litterale. Séparez plusieurs filtres par un espace.
# card select / image export
filename format: (Utilisez {card.name} pour le nom de la Carte ; Le type de fichier est déterminé, basé par l'extension)
filename format: (Utilisez {card.name} pour le nom de la carte ; Le type de fichier est déterminé, basé par l'extension)
# cards panel
collapse notes: Cacher les notes des Cartes
expand notes: Afficher les notes des Cartes
search cards control: Filtrer la liste des Cartes. Utilisez - pour exclure des Cartes. Utilisez field: pour rechercher uniquement dans un champ donné. Utilisez des guillemets pour une recherche litterale. Séparez plusieurs filtres par un espace.
collapse notes: Cacher les notes des cartes
expand notes: Afficher les notes des cartes
search cards control: Filtrer la liste des cartes. Utilisez - pour exclure des cartes. Utilisez field: pour rechercher uniquement dans un champ donné. Utilisez des guillemets pour une recherche litterale. Séparez plusieurs filtres par un espace.
# keywords panel
search keywords control: Filtrer la liste des mots-clefs. Utilisez - pour exclure des mots-clefs. Utilisez field: pour rechercher uniquement dans un champ donné. Utilisez des guillemets pour une recherche litterale. Séparez plusieurs filtres par un espace.
@@ -286,7 +284,7 @@ help:
pour que le changement prenne effet.
zoom export:
(Quand l'option est décochée, les
Cartes sont exportées à 100% de leur
cartes sont exportées à 100% de leur
taille et dans leur rotation normale.)
# apprentice export
@@ -369,7 +367,7 @@ tool:
console tab: Console
# cards toolbar
search cards: Rechercher des Cartes (Ctrl+K)
search cards: Rechercher des cartes (Ctrl+K)
stats card counts 1: %s Au total
stats card counts 2: %s Dans le filtre, %s Au total
card counts 2: %s Dans la sélection, %s Au total
@@ -444,12 +442,11 @@ tooltip:
redo: Rétablir%s
# cards toolbar
add card: Ajouter une Carte
add card double: Ajouter une Carte recto-verso
remove card: Supprimer la Carte sélectionnée
link card: Lier des Cartes à la Carte sélectionnée
copy card and links: Copier les Cartes sélectionnées et leurs Cartes liées
rotate card: Tourner la Carte
add card: Ajouter une carte
remove card: Supprimer la carte sélectionnée
link card: Lier des cartes à la carte sélectionnée
copy card and links: Copier les cartes sélectionnées et leurs cartes liées
rotate card: Tourner la carte
# keywords toolbar
add keyword: Ajouter un Mot-clef
@@ -516,7 +513,7 @@ tooltip:
label:
## app window items labels
# cards panel
card notes: Notes de Carte:
card notes: Notes de carte:
# keywords panel
search keywords: Recherche dans les mots-clefs (Ctrl+K)
@@ -545,18 +542,18 @@ label:
custom link selected: Générateur, Face Avant, Composant d'Assimilation, etc...
custom link linked: Jeton, Face Arrière, Résultat d'Assimilation, etc...
custom link undefined: Non Défini
linked cards relation: Choisissez le type de relation entre la Carte sélectionnée ('%s') et les Cartes liées:
linked cards relation: Choisissez le type de relation entre la carte sélectionnée ('%s') et les cartes liées:
selected card: Carte sélectionnée:
linked cards: Cartes liées:
select linked cards: Choisissez jusqu’à 4 Cartes liées:
select linked cards: Choisissez jusqu’à 4 cartes liées:
# bulk modification dialog
bulk modify selection: Quelles Cartes doivent être modifiées:
bulk modify all: Toutes les Cartes
bulk modify filtered: Les Cartes actuellement filtrées
bulk modify selected: Les Cartes actuellement sélectionnées
bulk modify predicate: Les Cartes qui vérifient un critère
bulk modify predicate description: Quel critère doit être vérifié pour que la Carte soit modifiée:
bulk modify selection: Quelles cartes doivent être modifiées:
bulk modify all: Toutes les cartes
bulk modify filtered: Les cartes actuellement filtrées
bulk modify selected: Les cartes actuellement sélectionnées
bulk modify predicate: Les cartes qui vérifient un critère
bulk modify predicate description: Quel critère doit être vérifié pour que la carte soit modifiée:
bulk modify predicate example: Example (petites créatures de M:tG):
bulk modify field: Quelle valeur doit être modifiée:
bulk modify mod description: Que doit être la nouvelle valeur:
@@ -575,7 +572,7 @@ label:
# new set dialog
game type: &Type de jeu:
style type: &Style des Carte:
style type: &Style des carte:
search game list: Filtrer les jeux
search stylesheet list: Filtrer les Styles
@@ -592,7 +589,7 @@ label:
dark mode no: Mode clair
dark mode yes: Mode sombre
app language: Langue de l'interface utilisateur (App Language)
card display: Affichage des Cartes
card display: Affichage des cartes
zoom: &Zoom:
import: Import
export: &Export
@@ -605,7 +602,7 @@ label:
external programs: Programmes externes
apprentice: &Apprentice:
apprentice exe: Executable Apprentice
export desc: Lors de l'exportation de Cartes en images:
export desc: Lors de l'exportation de cartes en images:
import desc: Lors de l'importation d'images pour les illustrations:
internal scale desc:
Taille à laquelle stocker les images en interne.
@@ -624,8 +621,8 @@ label:
# card select / image export dialogs
select cards: Cartes à exporter
select cards print: Selectionner les Cartes à imprimer
selected card count: %s Cartes seront exportées.
select cards print: Selectionner les cartes à imprimer
selected card count: %s cartes seront exportées.
filename format: &Format:
filename conflicts: &Gestion des doublons de fichiers:
export filenames: Nom des fichiers
@@ -649,7 +646,7 @@ label:
# JSON import dialog
add card json type: Type de fichier JSON:
add card json custom: Fichier JSON customisé
add card json path: Chemin vers la liste de Cartes à l'intérieur du fichier:
add card json path: Chemin vers la liste de cartes à l'intérieur du fichier:
add card json file: Chemin du fichier:
# image slicer dialog
@@ -712,18 +709,17 @@ label:
installable version: Dernière version:
installer size: Taille:
installer status: État:
folder name: Dossier:
no version: -
load image: Double-cliquer pour charger une image
# print dialog
put space between cards: Ajouter un espace entre les Cartes?
spacing print: Espace entre les Cartes en millimètres
put space between cards: Ajouter un espace entre les cartes?
spacing print: Espace entre les cartes en millimètres
bleed print: Marge de fond perdu en millimètres
cutter lines print: Ajouter des lignes de découpe?
cutter lines all: Toutes
cutter lines no intersect: Si elles n'intersectent pas de Carte
cutter lines no intersect: Si elles n'intersectent pas de carte
cutter lines none: Aucune
## symbol editor
@@ -736,8 +732,8 @@ button:
link select: Sélectionner
# style panel
use for all cards: Utiliser pour toutes les C&artes
use custom styling options: Options &spécifique à cette Carte
use for all cards: Utiliser pour toutes les c&artes
use custom styling options: Options &spécifique à cette carte
# set info panel
edit symbol: Éditer
@@ -777,9 +773,9 @@ button:
Ajoutez une marge de
fond perdu grossière
notes export:
Exporter les notes de la Carte à
Exporter les notes de la carte à
l'intérieur des Métadonnées de l'image
spellcheck enabled: Afficher les fautes d'orthographe sur les Cartes
spellcheck enabled: Afficher les fautes d'orthographe sur les cartes
check now: &Vérifier maintenant
always: Toujours
every 5 startups: Tous les 5 démarrages
@@ -805,7 +801,7 @@ button:
export entire set: Set complet
export generated packs: Packs générés
export custom cards selection: Sélection personalisée
select cards: &Sélection des Cartes...
select cards: &Sélection des cartes...
select all: Sélectionner &toutes
select none: Sélectionner &aucune
overwrite: Ecraser les anciens fichiers
@@ -828,13 +824,12 @@ button:
keep package: &Ne pas modifier
don't install package: &Ne pas installer
install package: &Installer
upgrade package: &Mettre à jour
upgrade package: &Upgrader
reinstall package: Ré&installer
remove package: &Supprimer
keep group: &Ne pas modifier le groupe
install group: &Installer/Mettre à jour le groupe
upgrade group: &Mettre à jour le groupe
remove group: &Supprimer le groupe
install group: &Installer Tout
upgrade group: &Upgrader Tout
remove group: &Supprimer Tout
############################################################## Titles in the GUI
title:
@@ -913,13 +908,12 @@ title:
############################################################## Action (undo/redo) names
action:
# cards
reorder cards: Réorganiser les Cartes
update card: Mettre à jour la Carte
reorder cards: Réorganiser les cartes
change link: Modifier le lien
change notes: Modifier les notes
change id: Modifier l'ID
change style: Modifier le style
change all styles: Modifier le style (toutes les Cartes)
change all styles: Modifier le style (toutes les cartes)
use custom style: Utiliser un style personnalisé
show reminder text: Afficher le texte de rappel
hide reminder text: Masquer le texte de rappel
@@ -1016,7 +1010,7 @@ error:
no field with name: Impossible de trouver le champ de %s nommé '%s'
styling data not map: La valeur donnée pour « %s_data » n'est pas un dictionnaire
styling data without stylesheet: Valeur donnée pour « %s_data » avant la définition d'un Style
cant set value: Impossible de définir la valeur de la Carte '%s', son type est incorrect
cant set value: Impossible de définir la valeur de la carte '%s', son type est incorrect
cant set image value: On ne peut définir la valeur d'une image qu'avec un nom de fichier relatif depuis le package, ou avec les fonctions import_image/download_image (dans le champ '%s')
cant set symbol value: On ne peut définir la valeur d'un symbol qu'avec un nom de fichier relatif depuis le package (dans le champ '%s')
add card csv file not found: Impossible de trouver ou charger le fichier CSV ou TSV spécifié
@@ -1053,15 +1047,14 @@ error:
# image stuff
coordinates for blending overlap: Les coordonnées pour le mélange sont superposées. Espacez-les.
blending different sizes: Les images utilisées pour le mélange doivent avoir la même taille dans la fonction '%s'. (L'une est %s, l'autre est %s)
blending different mask: L'image et le masque utilisés pour le mélange doivent avoir la même taille dans la fonction '%s'. (L'image est %s, le masque est %s)
blending different sizes: Les images utilisées pour le mélange doivent avoir la même taille dans la fonction '%s'.
negative image width: Image de largeur nulle ou négative créée par la fonction '%s'
negative image height: Image de hauteur nulle ou négative créée par la fonction '%s'
can't load image: Échec du chargement de l'image. Assurez-vous que le format réel de l'image corresponde à son extension enregistrée.
symbol image has alpha: Pour un résultat optimal, l'image doit être en noir et blanc sans transparence.
# error from files
no card fields: Le jeu '%s' ne contient aucun champ de Carte. Définissez au moins un champ de Carte.
no card fields: Le jeu '%s' ne contient aucun champ de carte. Définissez au moins un champ de carte.
reserved field name: '%s' est un nom de champ réservé. Veuillez utiliser un autre nom.
duplicate field name: Le nom de champ alternatif '%s' est un doublon : il sagit à la fois dun nom alternatif pour '%s' et '%s'.
no game specified: Pas de jeu spécifié pour le %s
@@ -1091,15 +1084,15 @@ error:
no updates: Il n'y a pas de mises à jour disponibles.
# card linking
not enough free links: La Carte '%s' n'a pas assez de liens disponibles. Vous pouvez former au maximum 4 liens par Carte.
not enough free links for copy: La Carte '%s' n'a pas assez de liens disponibles pour copier. Vous pouvez former au maximum 4 liens par Carte.
could not link: Les Cartes suivantes n'ont pas pu être liées, elles ont déjà 4 liens:
missing free links: La Carte ne contient que %s liens libres. Sélectionnez moins de Cartes.
not enough free links: La carte '%s' n'a pas assez de liens disponibles. Vous pouvez former au maximum 4 liens par carte.
not enough free links for copy: La carte '%s' n'a pas assez de liens disponibles pour copier. Vous pouvez former au maximum 4 liens par carte.
could not link: Les cartes suivantes n'ont pas pu être liées, elles ont déjà 4 liens:
missing free links: La carte ne contient que %s liens libres. Sélectionnez moins de cartes.
link duplicate: Nom de lien localisé dupliqué. '%s' correspond à la fois à '%s' et à '%s'.
multiple front faces: La Carte '%s' contient plusieurs Cartes liées comme face avant.
multiple back faces: La Carte '%s' contient plusieurs Cartes liées comme face arrière.
cant link to self: Impossible de lier une Carte à elle-même. (Cet assignation sera ignorée.)
no cards selected: Aucune Carte sélectionnée. Sélectionnez jusqu'à 4 Cartes à lier.
multiple front faces: La carte '%s' contient plusieurs cartes liées comme face avant.
multiple back faces: La carte '%s' contient plusieurs cartes liées comme face arrière.
cant link to self: Impossible de lier une carte à elle-même. (Cet assignation sera ignorée.)
no cards selected: Aucune carte sélectionnée. Sélectionnez jusqu'à 4 cartes à lier.
could not find input: Carte d'input introuvable.
could not find linked: Carte liée (linked_card) introuvable.
@@ -1109,11 +1102,11 @@ error:
bulk modify mod is not string: La modification doit être une chaîne de caractères, mais a été évaluée à %s.
bulk modify mod is not color: La modification doit être une couleur, mais a été évaluée à %s.
bulk modify mod is not image: La modification doit être une image, mais a été évaluée à %s. Utilisez les fonctions import_image/download_image pour définir les champs d' images.
bulk modify mod is nil: La modification est null pour la Carte '%s'. Elle ne sera pas appliquée.
bulk modify no cards: Aucune Carte à modifier.
bulk modify no cards verify: Aucune Carte ne correspond au critère.
bulk modify nothing: Aucune Carte n'a été modifiée.
bulk modify success: Nombre de Cartes modifiées avec succès : %s
bulk modify mod is nil: La modification est null pour la carte '%s'. Elle ne sera pas appliquée.
bulk modify no cards: Aucune carte à modifier.
bulk modify no cards verify: Aucune carte ne correspond au critère.
bulk modify nothing: Aucune carte n'a été modifiée.
bulk modify success: Nombre de cartes modifiées avec succès : %s
# web request
web request failed: Échec de la requête Web
@@ -1174,9 +1167,9 @@ type:
stylesheet: stylesheet
export template: modèle d'export
symbol: symbole
card: Carte
cards: Cartes
extra card: extra Carte
card: carte
cards: cartes
extra card: extra carte
field: champ
style: style
styling: style
@@ -1184,8 +1177,8 @@ type:
keyword: mot-clef
keywords: mots-clefs
pack: type de pack
card region: région de Carte
card regions: régions de Carte
card region: région de carte
card regions: régions de carte
# symbol editor shapes
shape: forme
+6 -13
View File
@@ -54,7 +54,6 @@ menu:
next card: Seleziona &carta successiva PgDn
search cards: Cerca carte Ctrl+K
add card: &Aggiungi carta Ctrl+Enter
add card double: Aggiungi carta fronte-retro Ctrl+Shift+Enter
add cards: Aggiungi &carte Multiple...
remove card: &Rimuovi carta Del
add card csv: Aggiungi carte da CSV o TSV...
@@ -197,7 +196,6 @@ help:
next card: Seleziona la prossima carta della lista
search cards: Filtra l'elenco delle carte utilizzando i termini di ricerca
add card: Aggiunge una nuova carta vuota al set
add card double: Aggiunge una nuova carta vuota con il retro al set
add cards: Aggiunge carte multiple al set
remove card: Cancella la carta selezionata dal set
link card: Collega una o più carte alla carta selezionata
@@ -445,7 +443,6 @@ tooltip:
# cards toolbar
add card: Aggiungi carta
add card double: Aggiungi carta fronte-retro
remove card: Rimuovi carta selezionata
link card: Collega alcune carte alla carta selezionata
copy card and links: Copia le carte selezionate e tutte le carte collegate
@@ -712,7 +709,6 @@ label:
installable version: Ultima versione:
installer size: Dimesioni:
installer status: Stato:
folder name: Nome:
no version: -
load image: Fai doppio clic per caricare un'immagine
@@ -825,16 +821,15 @@ button:
close: &Chiudi
# packages window
keep package: &Mantieni così com'è
keep package: &Non modificare
don't install package: &Non installare
install package: &Installa
upgrade package: Aggiorna
upgrade package: Aggiorna (&U)
reinstall package: Re&installa
remove package: &Rimuovi
keep group: Mantieni il gruppo così com'è
install group: &Installa/Aggiorna il gruppo
upgrade group: &Aggiorna il gruppo
remove group: &Rimuovi il gruppo
install group: &Installa Tutto
upgrade group: &Upgrade Tutto
remove group: &Rimuovi Tutto
############################################################## Titles in the GUI
title:
@@ -914,7 +909,6 @@ title:
action:
# cards
reorder cards: Riordina le carte
update card: Aggiorna la carta
change link: Modifica collegamento
change notes: Modifica note
change id: Modifica ID
@@ -1053,8 +1047,7 @@ error:
# image stuff
coordinates for blending overlap: Le coordinate per la fusione si sovrappongono.
blending different sizes: Le immagini utilizzate per la fusione devono avere le stesse dimensioni nella funzione '%s'. (Una è %s, l'altra è %s)
blending different mask: L'immagine e la maschera utilizzate per la fusione devono avere le stesse dimensioni nella funzione '%s'. (L'immagine è %s, la maschera è %s)
blending different sizes: Le immagini utilizzate per la fusione devono avere le stesse dimensioni nella funzione '%s'.
negative image width: Immagine con larghezza zero o negativa creata nella funzione '%s'.
negative image height: Immagine con altezza zero o negativa creata nella funzione '%s'.
can't load image: Impossibile caricare l'immagine. Assicurarsi che il formato effettivo dell'immagine corrisponda all'estensione salvata.
+1 -15
View File
@@ -54,8 +54,6 @@ menu:
next card: 次のカードを選択 PgDn
search cards: カードの検索 Ctrl+K
add card: &カードを追加 Ctrl+Enter
#TODO: Localize
add card double: &Add Double Faced Card Ctrl+Shift+Enter
add cards: &複数のカードを追加...
remove card: &選択したカードを削除
#TODO: Localize
@@ -210,8 +208,6 @@ help:
next card: リストの次のカードを選択します。
search cards: 検索語を使用してカードリストをフィルタリングする
add card: 新しいカードを現在のセットに加えます。
#TODO: Localize
add card double: Add a new, blank, card that has a back face to this set
add cards: 複数のカードを現在のセットに加えます。
remove card: 現在のセットから選ばれたカードを削除します。
#TODO: Localize
@@ -471,8 +467,6 @@ tooltip:
# cards toolbar
add card: カードを追加
#TODO: Localize
add card double: Add double faced card
remove card: 選択したカードを削除
#TODO: Localize
link card: Link cards to selected card
@@ -764,8 +758,6 @@ label:
installable version: 最新バージョン
installer size: サイズ
installer status: 状態
#TODO: Localize
folder name: Folder name:
no version: -
#TODO: Localize
@@ -898,8 +890,6 @@ button:
upgrade package: &アップグレード
reinstall package: 再インストール
remove package: &取り外す
#TODO: Localize
keep group: Keep Group As Is
install group: すべてインストールする
upgrade group: すべてアップグレードする
remove group: すべて削除する
@@ -992,8 +982,6 @@ action:
# cards
#TODO: Localize Section
reorder cards: Reorder cards
#TODO: Localize
update card: Update card
change link: Change link
change notes: Change notes
change id: Change ID
@@ -1143,9 +1131,7 @@ error:
# image stuff
coordinates for blending overlap: オーバーラップを混ぜることのための座標
#TODO: Localize
blending different sizes: Images used for blending must have the same size in function '%s' (one is %s, the other is %s)
#TODO: Localize
blending different mask: Image and mask used for blending must have the same size in function '%s' (image is %s, mask is %s)
blending different sizes: Images used for blending must have the same size in function '%s'
#TODO: Localize
negative image width: Image with zero or negative width created in function '%s'
#TODO: Localize
+1 -15
View File
@@ -54,8 +54,6 @@ menu:
next card: 다음 카드 PgDn
search cards: &카드 검색 Ctrl+K
add card: &카드 추가 Ctrl+Enter
#TODO: Localize
add card double: &Add Double Faced Card Ctrl+Shift+Enter
add cards: &여러 카드 추가...
remove card: &카드 삭제
#TODO: Localize
@@ -210,8 +208,6 @@ help:
next card: 목록에서 다음 카드를 선택합니다.
search cards: 검색어를 사용하여 카드 목록 필터링
add card: 이 세트에 새로운 빈 카드를 추가하세요.
#TODO: Localize
add card double: Add a new, blank, card that has a back face to this set
add cards: 세트에 여러 카드 추가
remove card: 이 세트에서 선택한 카드를 삭제하세요.
#TODO: Localize
@@ -477,8 +473,6 @@ tooltip:
# cards toolbar
add card: 카드 추가
#TODO: Localize
add card double: Add double faced card
remove card: 선택한 카드 삭제
#TODO: Localize
link card: Link cards to selected card
@@ -770,8 +764,6 @@ label:
installable version: 최신 버전:
installer size: 크기:
installer status: 상태:
#TODO: Localize
folder name: Folder name:
no version: -
#TODO: Localize
@@ -904,8 +896,6 @@ button:
upgrade package: 업데이트
reinstall package: 재설치
remove package: 제거하다
#TODO: Localize
keep group: Keep Group As Is
install group: 모두 설치
upgrade group: 모두 업그레이드
remove group: 모두 제거
@@ -998,8 +988,6 @@ action:
# cards
#TODO: Localize Section
reorder cards: Reorder cards
#TODO: Localize
update card: Update card
change link: Change link
change notes: Change notes
change id: Change ID
@@ -1149,9 +1137,7 @@ error:
# image stuff
coordinates for blending overlap: 블렌딩 오버랩을 위한 좌표
#TODO: Localize
blending different sizes: Images used for blending must have the same size in function '%s' (one is %s, the other is %s)
#TODO: Localize
blending different mask: Image and mask used for blending must have the same size in function '%s' (image is %s, mask is %s)
blending different sizes: Images used for blending must have the same size in function '%s'
#TODO: Localize
negative image width: Image with zero or negative width created in function '%s'
#TODO: Localize
+1 -15
View File
@@ -64,8 +64,6 @@ menu:
#TODO: Localize
search cards: &Search Cards Ctrl+K
add card: &Dodaj Kartę Ctrl+Enter
#TODO: Localize
add card double: &Add Double Faced Card Ctrl+Shift+Enter
add cards: Dodaj &Wiele Kart...
remove card: &Usuń Wybraną Kartę
#TODO: Localize
@@ -229,8 +227,6 @@ help:
#TODO: Localize
search cards: Filter the card list using search terms
add card: Dodaj nową, pustą kartę do zestawu
#TODO: Localize
add card double: Add a new, blank, card that has a back face to this set
add cards: Dodaj wiele kart do zestawu
remove card: Usuń wybraną kartę z zestawu
#TODO: Localize
@@ -506,8 +502,6 @@ tooltip:
# cards toolbar
add card: Dodaj kartę
#TODO: Localize
add card double: Add double faced card
remove card: Usuń wybraną kartę
#TODO: Localize
link card: Link cards to selected card
@@ -814,8 +808,6 @@ label:
installable version: Najnowsza wersja:
installer size: Rozmiar:
installer status: Stan:
#TODO: Localize
folder name: Folder name:
no version: -
#TODO: Localize
@@ -952,8 +944,6 @@ button:
upgrade package: &Uaktualnij
reinstall package: Zainstaluj &ponownie
remove package: &Usuń
#TODO: Localize
keep group: Keep Group As Is
install group: &Instaluj wszystkie
upgrade group: &Uaktualnij wszystkie
remove group: &Usuń wszystkie
@@ -1047,8 +1037,6 @@ action:
# cards
#TODO: Localize Section
reorder cards: Reorder cards
#TODO: Localize
update card: Update card
change link: Change link
change notes: Change notes
change id: Change ID
@@ -1199,9 +1187,7 @@ error:
# image stuff
coordinates for blending overlap: Współrzędne scalania (blending) nachodzą na siebie
#TODO: Localize
blending different sizes: Images used for blending must have the same size in function '%s' (one is %s, the other is %s)
#TODO: Localize
blending different mask: Image and mask used for blending must have the same size in function '%s' (image is %s, mask is %s)
blending different sizes: Images used for blending must have the same size in function '%s'
#TODO: Localize
negative image width: Image with zero or negative width created in function '%s'
#TODO: Localize
+7 -14
View File
@@ -54,7 +54,6 @@ menu:
next card: Selecionar Próximo ca&rd PgDn
search cards: &Procurar Cards Ctrl+K
add card: &Adicionar Card Ctrl+Enter
add card double: &Adicionar Card de dupla face Ctrl+Shift+Enter
add cards: Adicionar &Multiplos Cards...
remove card: &Deletar Card Selecionado
add card csv: Adicionar Cards de um arquivo CSV ou TSV...
@@ -195,9 +194,8 @@ help:
# cards menu
previous card: Seleciona o Card anterior da lista.
next card: Seleciona o próximo Card da lista.
search cards: Filtre a lista de Cards usando termos de pesquisa.
search cards: Filtre a lista de Cards usando termos de pesquisa
add card: Adicione um novo, em branco, Card para esta Edição.
add card double: Adicione um novo, em branco, Card com verso para esta Edição.
add cards: Adicione multiplos Cards à esta Edição.
remove card: Apaga o Card selecionado desta Edição.
link card: Vincular um ou mais Cards à Card selecionado
@@ -446,7 +444,6 @@ tooltip:
# cards toolbar
add card: Adiciona um Card
add card double: Adicionar um Card de dupla face
remove card: Remove o Card selecionado
link card: Vincular Cards ao Card selecionado
copy card and links: Copiar Cards selecionados e seus Cards vinculados
@@ -713,7 +710,6 @@ label:
installable version: Última versão:
installer size: Dimenções:
installer status: Status:
folder name: Nome da pasta:
no version: -
load image: Clique duas vezes para carregar uma imagem
@@ -826,16 +822,15 @@ button:
close: &Fechar
# packages window
keep package: Manter como está
keep package: Não& alterar
don't install package: Não& instalar
install package: &Instalar
upgrade package: &Atualizar
upgrade package: &Atualizações
reinstall package: Re&instalar
remove package: &Remover
keep group: &Manter o grupo como está
install group: &Instalar/Atualizar o grupo
upgrade group: &Atualizar o grupo
remove group: &Remover o grupo
install group: &Instalar Tudo
upgrade group: &Atualizar tudo
remove group: &Remover tudo
############################################################## Titles in the GUI
title:
@@ -915,7 +910,6 @@ title:
action:
# cards
reorder cards: Reordenar Cards
update card: Atualizar Card
change link: Alterar link
change notes: Alterar notas
change id: Alterar ID
@@ -1054,8 +1048,7 @@ error:
# image stuff
coordinates for blending overlap: As coordenadas para a mistura se sobrepõem.
blending different sizes: As imagens usadas para mesclagem devem ter o mesmo tamanho na função '%s'. (Uma é %s, a outra é %s)
blending different mask: A imagem e a máscara usadas para mesclagem devem ter o mesmo tamanho na função '%s' (Imagem é %s, máscara é %s)
blending different sizes: As imagens usadas para mesclagem devem ter o mesmo tamanho na função '%s'.
negative image width: Imagem com largura zero ou negativa criada na função '%s'
negative image height: Imagem com altura zero ou negativa criada na função '%s'
can't load image: Falha ao carregar a imagem. Verifique se o formato real da imagem corresponde à extensão salva.
+1 -15
View File
@@ -55,8 +55,6 @@ menu:
next card: Следующая карта PgDn
search cards: Найти карты Ctrl+K
add card: Добавить карту Ctrl+Enter
#TODO: Localize
add card double: &Add Double Faced Card Ctrl+Shift+Enter
add cards: Добавить несколько карт...
remove card: Удалить выделенную карту
#TODO: Localize
@@ -221,8 +219,6 @@ help:
next card: Выбрать следующую карту в списке
search cards: Отфильтруйте список карточек с помощью условий поиска
add card: Добавить новую карту в текущий сет
#TODO: Localize
add card double: Add a new, blank, card that has a back face to this set
add cards: Добавить несколько новых карт в текущий сет
remove card: Удалить выбранную карту из текущего сета
#TODO: Localize
@@ -494,8 +490,6 @@ tooltip:
# cards toolbar
add card: Добавить карту
#TODO: Localize
add card double: Add double faced card
remove card: Удалить выделенную карту
#TODO: Localize
link card: Link cards to selected card
@@ -804,8 +798,6 @@ label:
installable version: Последняя версия:
installer size: Размер:
installer status: Статус:
#TODO: Localize
folder name: Folder name:
no version: -
#TODO: Localize
@@ -940,8 +932,6 @@ button:
upgrade package: Обновить
reinstall package: Переустановить
remove package: Удалить
#TODO: Localize
keep group: Keep Group As Is
install group: Установить все
upgrade group: Обновить все
remove group: Удалить все
@@ -1035,8 +1025,6 @@ action:
# cards
#TODO: Localize Section
reorder cards: Reorder cards
#TODO: Localize
update card: Update card
change link: Change link
change notes: Change notes
change id: Change ID
@@ -1194,9 +1182,7 @@ error:
#TODO: Localize
coordinates for blending overlap: Coordinates for blending overlap. Space them out.
#TODO: Localize
blending different sizes: Images used for blending must have the same size in function '%s' (one is %s, the other is %s)
#TODO: Localize
blending different mask: Image and mask used for blending must have the same size in function '%s' (image is %s, mask is %s)
blending different sizes: Images used for blending must have the same size in function '%s'
#TODO: Localize
negative image width: Image with zero or negative width created in function '%s'
#TODO: Localize
-16
View File
@@ -1,16 +0,0 @@
Function: exists_as_package
--Usage--
> exists_as_package("package")
Check if a package exists in the data folder.
Returns the package's version number as major-minor-patch, or nil if the package does not exists.
--Parameters--
! Parameter Type Description
| @input@ [[type:string]] Full name of the package folder, including game and extension.
--Examples--
> exists_as_package("magic-modules.mse-include") == "2026-02-28"
> exists_as_package("magic-quadruple-faced-leveler.mse-style") == nil
-4
View File
@@ -78,7 +78,6 @@ These functions are built into the program, other [[type:function]]s can be defi
| [[fun:exclusive_choice]] Require that at most one of the given choices is selected.
| [[fun:require_exclusive_choice]] Require that exactly one of the given choices is selected.
| [[fun:remove_choice]] Remove the given choices from a multiple choice value.
| [[fun:is_default]] Check if a field is in its default state.
! Images <<<
| [[fun:linear_blend]] Blend two images together using a linear gradient.
@@ -109,7 +108,6 @@ These functions are built into the program, other [[type:function]]s can be defi
! Cards <<<
| [[fun:new_card]] Construct a new [[type:card]] object.
| [[fun:new_uid]] Construct a new uid.
| [[fun:add_card_to_set]] Add a [[type:card]] to a [[type:set]].
| [[fun:get_card_styling]] Get the styling data of a [[type:card]].
| [[fun:get_card_stylesheet]] Get the stylesheet of a [[type:card]].
@@ -138,6 +136,4 @@ These functions are built into the program, other [[type:function]]s can be defi
| [[fun:assert]] Check a condition for debugging purposes.
| [[fun:warning]] Output a warning message.
| [[fun:error]] Output an error message.
| [[fun:version_is_older]] Checks if a version number is older than another.
| [[fun:exists_as_package]] Checks if a package exists.
| [[fun:exists_in_package]] Checks if a file exists in a package.
-10
View File
@@ -1,10 +0,0 @@
Function: is_default
--Usage--
> is_default(some_field)
Returns true if the field is in its default state, that is, if the user hasn't modified the value yet, false otherwise.
--Parameters--
! Parameter Type Description
| @input@ [[type:field]] Field to test.
-10
View File
@@ -1,10 +0,0 @@
Function: new_uid
--Usage--
> new_uid()
Returns a new card uid, a string of 32 random digits, which is guaranteed to not exist in the set.
--Parameters--
! Parameter Type Description
| @set@ [[type:set]] The set in which to look for uid conflicts. This can be omitted since 'set' is a predefined variable.
-18
View File
@@ -1,18 +0,0 @@
Function: version_is_older
--Usage--
> version_is_older("version", than: "other version")
Check if a version number is strictly older than another.
Malformed version numbers, including nil, are treated as 0-0-0.
--Parameters--
! Parameter Type Description
| @input@ [[type:string]] Version we want to check.
| @than@ [[type:string]] Version we want to check against.
--Examples--
> version_is_older("2025-06-28", than: "2026-02-18") == true
> version_is_older("2026-02-18", than: "2026-02-18") == false
> version_is_older(nil, than: "0-0-1") == true
Binary file not shown.

Before

Width:  |  Height:  |  Size: 546 B

-1
View File
@@ -66,7 +66,6 @@ tool/dark_reminder IMAGE "tool/dark_reminder.png"
tool/no_auto IMAGE "tool/no_auto.png"
tool/card_add IMAGE "tool/card_add.png"
tool/card_add_double IMAGE "tool/card_add_double.png"
tool/card_add_multiple IMAGE "tool/card_add_multiple.png"
tool/card_modify_multiple IMAGE "tool/card_modify_multiple.png"
tool/card_del IMAGE "tool/card_del.png"
+18 -40
View File
@@ -30,6 +30,13 @@ AddCardAction::AddCardAction(AddingOrRemoving ar, Set& set, const vector<CardP>&
// We always assume uid conflicts occur because a card was copy-pasted into the same set,
// and never because two different cards randomly got assigned the same uid
if (!action.adding) return;
// Tally existing unique ids
unordered_map<String, CardP> all_existing_cards;
unordered_set<String> all_existing_uids;
FOR_EACH(card, set.cards) {
all_existing_cards.insert({ card->uid, card });
all_existing_uids.insert(card->uid);
}
// Tally added unique ids
unordered_map<String, CardP> all_added_uids;
for (size_t pos = 0; pos < action.steps.size(); ++pos) {
@@ -42,7 +49,7 @@ AddCardAction::AddCardAction(AddingOrRemoving ar, Set& set, const vector<CardP>&
String old_uid = added_pair.first;
CardP added_card = added_pair.second;
// Assign new unique id if necessary
if (set.card_uids.find(old_uid) == set.card_uids.end()) continue;
if (all_existing_cards.find(old_uid) == all_existing_cards.end()) continue;
String new_uid = generate_uid();
added_card->uid = new_uid;
all_added_uids.insert({ new_uid, added_card });
@@ -51,22 +58,21 @@ AddCardAction::AddCardAction(AddingOrRemoving ar, Set& set, const vector<CardP>&
FOR_EACH(linked_pair, linked_pairs) {
String& linked_uid = linked_pair.first.get();
if (linked_uid.empty()) continue;
// If it's an added card, update the link
// If it's an added card, replace the link
if (all_added_uids.find(linked_uid) != all_added_uids.end()) {
all_added_uids.at(linked_uid)->updateLinkedUID(old_uid, new_uid);
}
// Otherwise, if it's an existing card, create an action to copy the link
else if (set.card_uids.find(linked_uid) != set.card_uids.end()) {
CardP linked_card = set.card_uids.at(linked_uid);
int selected_index = linked_card->findUIDLink(old_uid);
if (selected_index < 0) continue;
int free_index = linked_card->findFreeLink(new_uid, set.card_uids);
if (free_index < 0) {
else if (all_existing_cards.find(linked_uid) != all_existing_cards.end()) {
CardP linked_card = all_existing_cards.at(linked_uid);
int linked_index = linked_card->findFreeLink(new_uid, all_existing_uids);
if (linked_index < 0) {
queue_message(MESSAGE_WARNING, _ERROR_1_("not enough free links", linked_card->identification()));
continue;
}
String selected_relation(linked_card->getLinkedRelation(selected_index));
card_link_actions.push_back(make_intrusive<OneWayLinkCardsAction>(linked_card, new_uid, selected_relation, free_index));
else {
String relation(linked_card->getLinkedRelation(linked_index));
card_link_actions.push_back(make_intrusive<OneWayLinkCardsAction>(linked_card, new_uid, relation, linked_index));
}
}
}
}
@@ -82,33 +88,6 @@ void AddCardAction::perform(bool to_undo) {
// Update card links
for (size_t i = 0; i < card_link_actions.size(); ++i) {
card_link_actions[i]->perform(to_undo);
}
// Update uid map
set.buildUIDMap();
}
UpdateCardAction::UpdateCardAction(Set& set, const vector<CardP>& cards_to_add, const vector<CardP>& cards_to_remove)
: CardListAction(set)
, action_add(ADD, set, cards_to_add)
, action_remove(REMOVE, set, cards_to_remove)
{}
String UpdateCardAction::getName(bool to_undo) const {
return _ACTION_("update card");
}
void UpdateCardAction::perform(bool to_undo) {
if (to_undo) {
action_remove.perform(to_undo);
set.actions.tellListeners(action_remove, to_undo);
action_add.perform(to_undo);
set.actions.tellListeners(action_add, to_undo);
}
else {
action_add.perform(to_undo);
set.actions.tellListeners(action_add, to_undo);
action_remove.perform(to_undo);
set.actions.tellListeners(action_remove, to_undo);
}
}
@@ -270,8 +249,7 @@ void ChangeCardUIDAction::perform(bool to_undo) {
FOR_EACH(c, set.cards) {
c->updateLinkedUID(card->uid, uid);
}
swap(card->uid, uid);
set.buildUIDMap();
swap(card->uid, uid);
}
// ----------------------------------------------------------------------------- : Pack types
-12
View File
@@ -50,18 +50,6 @@ public:
vector<ActionP> card_link_actions;
};
/// Update one or more cards from a set by replacing them with other cards
class UpdateCardAction : public CardListAction {
public:
UpdateCardAction(Set& set, const vector<CardP>& cards_to_add, const vector<CardP>& cards_to_remove);
String getName(bool to_undo) const override;
void perform(bool to_undo) override;
AddCardAction action_add;
AddCardAction action_remove;
};
// ----------------------------------------------------------------------------- : Reorder cards
/// Change the position of a card in the card list by swapping two cards
+2 -4
View File
@@ -400,10 +400,8 @@ String BulkAction::getName(bool to_undo) const {
return to_undo ? name_undo : name_do;
}
void BulkAction::perform(bool to_undo) {
size_t size = actions.size();
for (size_t i = 0 ; i < size ; ++i) {
ActionP& action = actions[to_undo ? size - i - 1 : i];
void BulkAction::perform(bool to_undo) {
FOR_EACH(action, actions) {
action->perform(to_undo);
set->actions.tellListeners(*action, to_undo);
}
+5 -9
View File
@@ -25,22 +25,18 @@ IMPLEMENT_REFLECTION_NO_SCRIPT(AddCardsScript) {
void AddCardsScript::perform(Set& set, vector<CardP>& out) {
// Perform script
Context& ctx = set.getContext();
if (enabled.hasBeenRead()) {
enabled.update(ctx);
if (!enabled()) return;
}
Context& ctx = set.getContext();
ScriptValueP result = script.invoke(ctx);
// Add cards to out
ScriptValueP it = result->makeIterator();
while (ScriptValueP item = it->next()) {
CardP new_card = from_script<CardP>(item);
CardP card = from_script<CardP>(item);
// is this a new card?
if (contains(set.cards,new_card) || contains(out,new_card)) {
if (contains(set.cards,card) || contains(out,card)) {
// make copy
new_card = make_intrusive<Card>(&set, new_card);
card = make_intrusive<Card>(*card);
}
out.push_back(new_card);
out.push_back(card);
}
}
+47 -126
View File
@@ -42,38 +42,7 @@ Card::Card(Game& game)
, has_styling(false)
{
data.init(game.card_fields);
}
Card::Card(Set* set, const CardP& card)
: game(card->game)
, time_created (wxDateTime::Now())
, time_modified(wxDateTime::Now())
, notes(card->notes)
, uid(generate_uid())
, linked_card_1(card->linked_card_1)
, linked_card_2(card->linked_card_2)
, linked_card_3(card->linked_card_3)
, linked_card_4(card->linked_card_4)
, linked_relation_1(card->linked_relation_1)
, linked_relation_2(card->linked_relation_2)
, linked_relation_3(card->linked_relation_3)
, linked_relation_4(card->linked_relation_4)
, has_styling(card->has_styling)
, stylesheet_version(card->stylesheet_version)
, stylesheet(card->stylesheet)
{
if (!stylesheet && set) {
stylesheet = set->stylesheetForP(card);
}
if (has_styling) {
styling_data.cloneFrom(card->styling_data);
}
else {
if (stylesheet && set) styling_data.cloneFrom(set->stylingDataFor(*stylesheet));
}
data.cloneFrom(card->data);
extra_data.cloneFrom(card->extra_data);
}
}
String Card::identification() const {
// an identifying field
@@ -98,7 +67,7 @@ bool Card::contains(QuickFilterPart const& query) const {
return false;
}
vector<int> Card::findFreeLinks(vector<String>& linked_uids, const unordered_map<String, CardP>& all_existing_uids) {
vector<int> Card::findFreeLinks(vector<String>& linked_uids, const unordered_set<String>& all_existing_uids) {
vector<int> freeIndexes;
int count = min(4, (int)linked_uids.size());
LINK_PAIRS(linked_pairs, this);
@@ -140,7 +109,7 @@ vector<int> Card::findFreeLinks(vector<String>& linked_uids, const unordered_map
}
return freeIndexes;
}
int Card::findFreeLink(const String& linked_uid, const unordered_map<String, CardP>& all_existing_uids) {
int Card::findFreeLink(const String& linked_uid, const unordered_set<String>& all_existing_uids) {
vector<String> linked_uids { linked_uid };
return findFreeLinks(linked_uids, all_existing_uids)[0];
}
@@ -186,26 +155,12 @@ void Card::updateLinkedUID(const String& old_uid, const String& new_uid) {
if (index >= 0) getLinkedUID(index) = new_uid;
}
//vector<CardP> Card::getLinkedRelationCards(const vector<CardP>& cards, const String& linked_relation, bool erase_if_no_card) {
// vector<CardP> other_cards;
// vector<int> indexes = findRelationLinks(linked_relation);
// for (size_t i = 0; i < indexes.size(); ++i) {
// String& linked_uid = getLinkedUID(indexes[i]);
// CardP other_card = getUIDCard(cards, linked_uid);
// if (other_card) other_cards.push_back(other_card);
// else if (erase_if_no_card) {
// linked_uid = _("");
// getLinkedRelation(indexes[i]) = _("");
// }
// }
// return other_cards;
//}
vector<CardP> Card::getLinkedRelationCards(const Set& set, const String& linked_relation, bool erase_if_no_card) {
vector<CardP> Card::getLinkedRelationCards(const vector<CardP>& cards, const String& linked_relation, bool erase_if_no_card) {
vector<CardP> other_cards;
vector<int> indexes = findRelationLinks(linked_relation);
for (size_t i = 0; i < indexes.size(); ++i) {
String& linked_uid = getLinkedUID(indexes[i]);
CardP other_card = getUIDCard(set, linked_uid);
CardP other_card = getUIDCard(cards, linked_uid);
if (other_card) other_cards.push_back(other_card);
else if (erase_if_no_card) {
linked_uid = _("");
@@ -214,76 +169,51 @@ vector<CardP> Card::getLinkedRelationCards(const Set& set, const String& linked_
}
return other_cards;
}
vector<CardP> Card::getLinkedRelationCards(const Set& set, const String& linked_relation, bool erase_if_no_card) {
return getLinkedRelationCards(set.cards, linked_relation, erase_if_no_card);
}
//vector<pair<CardP, String>> Card::getLinkedCards(const vector<CardP>& cards) {
// unordered_map<String, String> links{
// { linked_card_1, linked_relation_1 },
// { linked_card_2, linked_relation_2 },
// { linked_card_3, linked_relation_3 },
// { linked_card_4, linked_relation_4 }
// };
// vector<pair<CardP, String>> linked_cards;
// FOR_EACH(other_card, cards) {
// if (links.find(other_card->uid) != links.end()) {
// linked_cards.push_back(make_pair(other_card, links.at(other_card->uid)));
// }
// }
// return linked_cards;
//}
vector<pair<CardP, String>> Card::getLinkedCards(const Set& set) {
vector<pair<CardP, String>> Card::getLinkedCards(const vector<CardP>& cards) {
unordered_map<String, String> links{
{ linked_card_1, linked_relation_1 },
{ linked_card_2, linked_relation_2 },
{ linked_card_3, linked_relation_3 },
{ linked_card_4, linked_relation_4 }
};
vector<pair<CardP, String>> linked_cards;
CardP other_card_1 = getUIDCard(set, linked_card_1);
if (other_card_1) {
linked_cards.push_back(make_pair(other_card_1, linked_relation_1));
}
CardP other_card_2 = getUIDCard(set, linked_card_2);
if (other_card_2) {
linked_cards.push_back(make_pair(other_card_2, linked_relation_2));
}
CardP other_card_3 = getUIDCard(set, linked_card_3);
if (other_card_3) {
linked_cards.push_back(make_pair(other_card_3, linked_relation_3));
}
CardP other_card_4 = getUIDCard(set, linked_card_4);
if (other_card_4) {
linked_cards.push_back(make_pair(other_card_4, linked_relation_4));
FOR_EACH(other_card, cards) {
if (links.find(other_card->uid) != links.end()) {
linked_cards.push_back(make_pair(other_card, links.at(other_card->uid)));
}
}
return linked_cards;
}
vector<pair<CardP, String>> Card::getLinkedCards(const Set& set) {
return getLinkedCards(set.cards);
}
//CardP Card::getLinkedOtherFaceCard(const vector<CardP>& cards) {
// unordered_set<String> faces;
// if (linked_relation_1 == _("Front Face") || linked_relation_1 == _("Back Face")) faces.emplace(linked_card_1);
// if (linked_relation_2 == _("Front Face") || linked_relation_2 == _("Back Face")) faces.emplace(linked_card_2);
// if (linked_relation_3 == _("Front Face") || linked_relation_3 == _("Back Face")) faces.emplace(linked_card_3);
// if (linked_relation_4 == _("Front Face") || linked_relation_4 == _("Back Face")) faces.emplace(linked_card_4);
// FOR_EACH(other_card, cards) {
// if (faces.find(other_card->uid) != faces.end()) return other_card;
// }
// return nullptr;
//}
CardP Card::getLinkedOtherFaceCard(const Set& set) {
if (linked_relation_1 == _("Front Face") || linked_relation_1 == _("Back Face")) {
CardP other_card_1 = getUIDCard(set, linked_card_1);
if (other_card_1) return other_card_1;
}
if (linked_relation_2 == _("Front Face") || linked_relation_2 == _("Back Face")) {
CardP other_card_2 = getUIDCard(set, linked_card_2);
if (other_card_2) return other_card_2;
}
if (linked_relation_3 == _("Front Face") || linked_relation_3 == _("Back Face")) {
CardP other_card_3 = getUIDCard(set, linked_card_3);
if (other_card_3) return other_card_3;
}
if (linked_relation_4 == _("Front Face") || linked_relation_4 == _("Back Face")) {
CardP other_card_4 = getUIDCard(set, linked_card_4);
if (other_card_4) return other_card_4;
CardP Card::getLinkedOtherFaceCard(const vector<CardP>& cards) {
unordered_set<String> faces;
if (linked_relation_1 == _("Front Face") || linked_relation_1 == _("Back Face")) faces.emplace(linked_card_1);
if (linked_relation_2 == _("Front Face") || linked_relation_2 == _("Back Face")) faces.emplace(linked_card_2);
if (linked_relation_3 == _("Front Face") || linked_relation_3 == _("Back Face")) faces.emplace(linked_card_3);
if (linked_relation_4 == _("Front Face") || linked_relation_4 == _("Back Face")) faces.emplace(linked_card_4);
FOR_EACH(other_card, cards) {
if (faces.find(other_card->uid) != faces.end()) return other_card;
}
return nullptr;
}
CardP Card::getLinkedOtherFaceCard(const Set& set) {
return getLinkedOtherFaceCard(set.cards);
}
void Card::addLink(const Set& set, CardP& linked_card, const String& selected_relation, const String& linked_relation) {
int index = findFreeLink(linked_card->uid, set.card_uids);
unordered_set<String> all_existing_uids;
FOR_EACH(card, set.cards) {
all_existing_uids.insert(card->uid);
}
int index = findFreeLink(linked_card->uid, all_existing_uids);
if (index < 0) {
queue_message(MESSAGE_ERROR, _ERROR_1_("not enough free links", identification()));
return;
@@ -291,7 +221,7 @@ void Card::addLink(const Set& set, CardP& linked_card, const String& selected_re
getLinkedUID(index) = linked_card->uid;
getLinkedRelation(index) = linked_relation;
index = linked_card->findFreeLink(uid, set.card_uids);
index = linked_card->findFreeLink(uid, all_existing_uids);
if (index < 0) {
queue_message(MESSAGE_ERROR, _ERROR_1_("not enough free links", linked_card->identification()));
}
@@ -316,19 +246,15 @@ void Card::removeLink(const CardP& linked_card)
}
}
//CardP Card::getUIDCard(const vector<CardP>& cards, const String& uid) {
// FOR_EACH(card, cards) {
// if (card->uid == uid) return card;
// }
// return nullptr;
//}
CardP Card::getUIDCard(const Set& set, const String& uid) {
auto it = set.card_uids.find(uid);
if (it != set.card_uids.end()) {
return it->second;
CardP Card::getUIDCard(const vector<CardP>& cards, const String& uid) {
FOR_EACH(card, cards) {
if (card->uid == uid) return card;
}
return nullptr;
}
CardP Card::getUIDCard(const Set& set, const String& uid) {
return getUIDCard(set.cards, uid);
}
IndexMap<FieldP, ValueP>& Card::extraDataFor(const StyleSheet& stylesheet) {
return extra_data.get(stylesheet.name(), stylesheet.extra_card_fields);
@@ -375,12 +301,7 @@ void reflect_version_check(GetDefaultMember& handler, const Char* key, intrusive
IMPLEMENT_REFLECTION(Card) {
REFLECT(stylesheet);
if (Handler::isReading) {
REFLECT_NO_SCRIPT(stylesheet_version);
}
else {
reflect_version_check(handler, _("stylesheet_version"), stylesheet);
}
reflect_version_check(handler, _("stylesheet_version"), stylesheet);
REFLECT(has_styling);
if (has_styling) {
if (stylesheet) {
+7 -11
View File
@@ -35,8 +35,6 @@ public:
Card();
/// Creates a card using the given game
Card(Game& game);
/// Copy constructor, makes a deep copy
Card(Set* set, const CardP& card);
/// The game this card is made for
Game* game;
@@ -62,9 +60,7 @@ public:
wxDateTime time_created, time_modified;
/// Alternative style to use for this card
/** Optional; if not set use the card style from the set */
StyleSheetP stylesheet;
/// What version of the stylesheet was this card using when it was last saved?
Version stylesheet_version;
StyleSheetP stylesheet;
/// Alternative options to use for this card, for this card's stylesheet
/** Optional; if not set use the styling data from the set.
* If stylesheet is set then contains data for the this->stylesheet, otherwise for set->stylesheet
@@ -110,8 +106,8 @@ public:
}
/// Find the index of a free link slot to write to. Returns -1 if not found.
int findFreeLink (const String& linked_uid, const unordered_map<String, CardP>& all_existing_uids);
vector<int> findFreeLinks(vector<String>& linked_uids, const unordered_map<String, CardP>& all_existing_uids);
int findFreeLink (const String& linked_uid, const unordered_set<String>& all_existing_uids);
vector<int> findFreeLinks(vector<String>& linked_uids, const unordered_set<String>& all_existing_uids);
/// Find the index of a link slot that references the linked_uid. Returns -1 if not found.
int findUIDLink(const String& linked_uid);
@@ -129,18 +125,18 @@ public:
//void updateLinkedRelation(const String& old_relation, const String& new_relation);
/// Get the card with the given uid.
//static CardP getUIDCard(const vector<CardP>& cards, const String& uid);
static CardP getUIDCard(const vector<CardP>& cards, const String& uid);
static CardP getUIDCard(const Set& set, const String& uid);
/// Get all the cards linked to this card with the given relation.
//vector<CardP> getLinkedRelationCards(const vector<CardP>& cards, const String& linked_relation, bool erase_if_no_card = true);
vector<CardP> getLinkedRelationCards(const vector<CardP>& cards, const String& linked_relation, bool erase_if_no_card = true);
vector<CardP> getLinkedRelationCards(const Set& set, const String& linked_relation, bool erase_if_no_card = true);
/// Get all the cards linked to this card.
//vector<pair<CardP, String>> getLinkedCards(const vector<CardP>& cards);
vector<pair<CardP, String>> getLinkedCards(const vector<CardP>& cards);
vector<pair<CardP, String>> getLinkedCards(const Set& set);
/// Get the back face or front face of this card.
//CardP getLinkedOtherFaceCard(const vector<CardP>& cards);
CardP getLinkedOtherFaceCard(const vector<CardP>& cards);
CardP getLinkedOtherFaceCard(const Set& set);
/// Link a card to this card.
-4
View File
@@ -305,10 +305,6 @@ bool Value::equals(const Value* that) {
return this == that;
}
bool Value::isDefault() {
return false;
}
bool Value::update(Context& ctx) {
updateAge();
updateSortValue(ctx);
+1 -3
View File
@@ -255,9 +255,7 @@ public:
virtual ValueP clone() const = 0;
/// Convert this value to a string for use in tables
virtual String toString() const = 0;
/// Check if this value is in the default state
virtual bool isDefault();
virtual String toString() const = 0;
/// Apply scripts to this value, return true if the value has changed
virtual bool update(Context& ctx);
/// This value has been updated by an action
+1 -6
View File
@@ -317,12 +317,7 @@ ChoiceValue::ChoiceValue(const ChoiceFieldP& field, bool initial_first_choice)
String ChoiceValue::toString() const {
return value();
}
bool ChoiceValue::isDefault() {
return value.isDefault();
}
}
bool ChoiceValue::update(Context& ctx) {
bool change = field().default_script.invokeOnDefault(ctx, value)
| field(). script.invokeOn(ctx, value);
+1 -3
View File
@@ -199,9 +199,7 @@ public:
DECLARE_VALUE_TYPE(Choice, Defaultable<String>);
ValueType value; /// The name of the selected choice
bool isDefault() override;
bool update(Context&) override;
};
-5
View File
@@ -110,12 +110,7 @@ String ColorValue::toString() const {
if (value() == c->color) return c->name;
}
return _("<color>");
}
bool ColorValue::isDefault() {
return value.isDefault();
}
bool ColorValue::update(Context& ctx) {
bool change = field().default_script.invokeOnDefault(ctx, value)
| field(). script.invokeOn(ctx, value);
+1 -3
View File
@@ -77,9 +77,7 @@ public:
DECLARE_VALUE_TYPE(Color, Defaultable<Color>);
ValueType value; ///< The value
bool isDefault() override;
bool update(Context&) override;
};
-4
View File
@@ -39,10 +39,6 @@ String ImageValue::toString() const {
return filename.empty() ? _("") : _("<image>");
}
bool ImageValue::isDefault() {
return filename.empty();
}
// custom reflection: convert to ScriptImageP for scripting
void ImageValue::reflect(Reader& handler) {
+1 -3
View File
@@ -47,9 +47,7 @@ public:
}
ValueType filename; ///< Filename of the image (in the current package), or ""
Age last_update; ///< When was the image last changed?
bool isDefault() override;
Age last_update; ///< When was the image last changed?
};
// ----------------------------------------------------------------------------- : ImageStyle
-5
View File
@@ -62,12 +62,7 @@ IMPLEMENT_REFLECTION(InfoStyle) {
String InfoValue::toString() const {
return value;
}
bool InfoValue::isDefault() {
return true;
}
bool InfoValue::update(Context& ctx) {
if (value.empty()) value = field().caption.get();
bool change = field().script.invokeOn(ctx, value);
+1 -3
View File
@@ -60,9 +60,7 @@ public:
DECLARE_VALUE_TYPE(Info, String);
ValueType value;
bool isDefault() override;
bool update(Context&) override;
};
-4
View File
@@ -52,10 +52,6 @@ IMPLEMENT_REFLECTION_NAMELESS(MultipleChoiceValue) {
REFLECT_BASE(ChoiceValue);
}
bool MultipleChoiceValue::isDefault() {
return value.isDefault();
}
bool MultipleChoiceValue::update(Context& ctx) {
String old_value = value();
ctx.setVariable(_("last_change"), to_script(last_change));
+1 -3
View File
@@ -63,9 +63,7 @@ public:
/// Splits the value, stores the selected choices in the out parameter
void get(vector<String>& out) const;
bool isDefault() override;
bool update(Context&) override;
private:
-6
View File
@@ -62,12 +62,6 @@ PackagedP PackageChoiceValue::getPackage() const {
else return package_manager.openAny(package_name, true);
}
bool PackageChoiceValue::isDefault() {
PackageChoiceFieldP packageFieldP = boost::dynamic_pointer_cast<PackageChoiceField>(fieldP);
if (packageFieldP) return package_name == packageFieldP->initial;
return false;
}
bool PackageChoiceValue::update(Context& ctx) {
bool change = field().script.invokeOn(ctx, package_name);
Value::update(ctx);
+1 -3
View File
@@ -61,9 +61,7 @@ public:
/// Get the package (if it is set), otherwise return nullptr
PackagedP getPackage() const;
bool isDefault() override;
bool update(Context&) override;
};
-4
View File
@@ -51,10 +51,6 @@ String SymbolValue::toString() const {
return filename.empty() ? _("") : _("<symbol>");
}
bool SymbolValue::isDefault() {
return filename.empty();
}
IMPLEMENT_REFLECTION_NO_GET_MEMBER(SymbolValue) {
if (fieldP->save_value || !handler.isWriting) REFLECT_NAMELESS(filename);
}
+1 -3
View File
@@ -69,8 +69,6 @@ public:
DECLARE_VALUE_TYPE(Symbol, LocalFileName);
ValueType filename; ///< Filename of the symbol (in the current package)
Age last_update; ///< When was the symbol last changed?
bool isDefault() override;
Age last_update; ///< When was the symbol last changed?
};
-5
View File
@@ -176,12 +176,7 @@ IMPLEMENT_REFLECTION(TextStyle) {
String TextValue::toString() const {
return untag_hide_sep(value());
}
bool TextValue::isDefault() {
return value.isDefault();
}
bool TextValue::update(Context& ctx) {
updateAge();
WITH_DYNAMIC_ARG(last_update_age, last_update.get());
+1 -3
View File
@@ -112,9 +112,7 @@ public:
ValueType value; ///< The text of this value
Age last_update; ///< When was the text last changed?
bool isDefault() override;
bool update(Context&) override;
};
+25 -48
View File
@@ -61,11 +61,9 @@ IMPLEMENT_REFLECTION(WrappedCards) {
}
wxDataFormat CardsDataObject::format(wxString("application/x-mse-cards"));
wxDataFormat CardsDataObject::format(wxString("application/x-mse-cards"));
CardsDataObject::CardsDataObject(const SetP& set, const String& id, const vector<CardP>& cards)
: wxCustomDataObject(format)
{
CardsDataObject::CardsDataObject(const SetP& set, const String id, const vector<CardP>& cards) {
// set the stylesheet, so when deserializing we know whos style options we are reading
vector<bool> has_styling;
for (size_t i = 0 ; i < cards.size() ; ++i) {
@@ -74,15 +72,9 @@ CardsDataObject::CardsDataObject(const SetP& set, const String& id, const vector
cards[i]->stylesheet = set->stylesheet;
}
}
// store as raw bytes
WrappedCards data = { set->game.get(), set->game->name(), id, cards };
String serialized = serialize_for_clipboard(*set, data);
wxScopedCharBuffer utf8 = serialized.utf8_str();
buffer.assign(utf8.data(), utf8.length());
SetData(buffer.size(), buffer.data());
// restore styling
SetText(serialize_for_clipboard(*set, data));
// restore cards
for (size_t i = 0 ; i < cards.size() ; ++i) {
if (has_styling[i]) {
cards[i]->stylesheet = StyleSheetP();
@@ -91,31 +83,22 @@ CardsDataObject::CardsDataObject(const SetP& set, const String& id, const vector
SetFormat(format);
}
CardsDataObject::CardsDataObject()
: wxCustomDataObject(format)
{}
CardsDataObject::CardsDataObject() {
SetFormat(format);
}
bool CardsDataObject::getCards(const SetP& set, const String& id, vector<CardP>& out) {
size_t size = GetSize();
if (size == 0) return false;
const void* raw = GetData();
if (!raw) return false;
String text(wxString::FromUTF8(static_cast<const char*>(raw), size));
bool CardsDataObject::getCards(const SetP& set, const String id, vector<CardP>& out) {
WrappedCards data = { set->game.get(), set->game->name() };
try {
deserialize_from_clipboard(data, *set, text);
} catch (...) {
queue_message(MESSAGE_ERROR, _("DEBUG: Card deserialization failed"));
return false;
}
deserialize_from_clipboard(data, *set, GetText());
if (data.cards.empty()) return false;
if (!id.empty() && data.id == id) return false;
if (data.game_name != set->game->name()) return false;
// Cards are from the same game
out = data.cards;
return true;
if (data.game_name == set->game->name()) {
// Cards are from the same game
out = data.cards;
return true;
} else {
return false;
}
}
// ----------------------------------------------------------------------------- : KeywordDataObject
@@ -156,34 +139,28 @@ KeywordP KeywordDataObject::getKeyword(const SetP& set) {
deserialize_from_clipboard(data, *set, GetText());
if (data.game_name != set->game->name()) return KeywordP(); // Keyword is from a different game
else return keyword;
}
}
// ----------------------------------------------------------------------------- : Card on clipboard
CardsOnClipboard::CardsOnClipboard(const SetP& set, const String id, const vector<CardP>& cards) {
wxBusyCursor busy;
// Conversion to image file
if (cards.size() < 6) {
Bitmap bmp;
Image img;
if (cards.size() == 1) {
img = export_image(set, cards[0], true, 1.0, 0.0, 0.0, &bmp);
img = export_image(set, cards[0]);
}
else {
img = export_image(set, cards);
bmp = Bitmap(img);
img = export_image(set, cards);
}
//wxFileDataObject* fileData = new wxFileDataObject(); // needed for pasting on desktop, but slow
//String temp_path = wxFileName::CreateTempFileName(_("mse")) + _(".png");
//img.SaveFile(temp_path, wxBITMAP_TYPE_PNG);
//fileData->AddFile(temp_path);
//Add(fileData);
wxImageDataObject* imgData = new wxImageDataObject(); // needed for metadata
String temp_path = wxFileName::CreateTempFileName(_("mse")) + _(".png");
img.SaveFile(temp_path, wxBITMAP_TYPE_PNG);
wxFileDataObject* fileData = new wxFileDataObject();
fileData->AddFile(temp_path);
Add(fileData);
wxImageDataObject* imgData = new wxImageDataObject();
imgData->SetImage(img);
Add(imgData);
wxBitmapDataObject* bmpData = new wxBitmapDataObject(); // needed for pasting in MSPaint
bmpData->SetBitmap(bmp);
Add(bmpData);
}
// Conversion to serialized card format
Add(new CardsDataObject(set, id, cards), true);
+5 -8
View File
@@ -18,23 +18,20 @@ DECLARE_POINTER_TYPE(Keyword);
// ----------------------------------------------------------------------------- : CardDataObject
/// The data format for cards on the clipboard
class CardsDataObject : public wxCustomDataObject {
class CardsDataObject : public wxTextDataObject {
public:
/// Name of the format of MSE cards
static wxDataFormat format;
CardsDataObject();
/// Store a card
CardsDataObject(const SetP& set, const String& id, const vector<CardP>& cards);
CardsDataObject(const SetP& set, const String id, const vector<CardP>& cards);
/// Retrieve the cards, only if this is made with the same game as set
/// And if this is NOT of the same id as the given one
/** Return true if the cards are correctly retrieved, and there is at least one card */
bool getCards(const SetP& set, const String& id, vector<CardP>& out);
private:
std::string buffer; // keep data alive for wx
};
bool getCards(const SetP& set, const String id, vector<CardP>& out);
};
// ----------------------------------------------------------------------------- : KeywordDataObject
@@ -47,7 +44,7 @@ public:
KeywordDataObject();
/// Store a keyword
KeywordDataObject(const SetP& set, const KeywordP& card);
/// Retrieve a keyword, only if it is made with the same game as set
KeywordP getKeyword(const SetP& set);
};
+1 -1
View File
@@ -89,7 +89,7 @@ FileFormatP mtg_editor_file_format();
// ----------------------------------------------------------------------------- : Other ways to export
/// Generate a wxImage of one or more cards
Image export_image(const SetP& set, const CardP& card, bool write_metadata = true, double zoom = 1.0, Radians angle_radians = 0.0, double bleed_pixels = 0.0, Bitmap* out_bitmap = nullptr);
Image export_image(const SetP& set, const CardP& card, bool write_metadata = true, double zoom = 1.0, Radians angle_radians = 0.0, double bleed_pixels = 0.0);
Image export_image(const SetP& set, const vector<CardP>& cards, int padding = 2, double global_zoom = 1.0, bool use_zoom_setting = true, bool use_rotation_setting = true, bool use_bleed_setting = false);
/// Export the image of one or more cards to a given filename, using the app's zoom, rotation and bleed settings, and including metadata
+3 -5
View File
@@ -35,7 +35,7 @@ Rotation ZoomedUnrotatedDataViewer::getRotation() const {
// ----------------------------------------------------------------------------- : wxImage export
Image export_image(const SetP& set, const CardP& card, bool write_metadata, double zoom, Radians angle_radians, double bleed_pixels, Bitmap* out_bitmap) {
Image export_image(const SetP& set, const CardP& card, bool write_metadata, double zoom, Radians angle_radians, double bleed_pixels) {
if (!set) throw Error(_("no set"));
/// create and zoom
ZoomedUnrotatedDataViewer viewer = ZoomedUnrotatedDataViewer(zoom);
@@ -51,9 +51,6 @@ Image export_image(const SetP& set, const CardP& card, bool write_metadata, doub
viewer.draw(dc);
dc.SelectObject(wxNullBitmap);
Image img = bitmap.ConvertToImage();
/// return bitmap if needed
if (out_bitmap) *out_bitmap = std::move(bitmap);
/// rotate
img = rotate_image(img, angle_radians);
@@ -221,7 +218,8 @@ void export_image(const SetP& set, const CardP& card, const String& filename) {
img.SaveFile(filename);
}
void export_image(const SetP& set, const vector<CardP>& cards, const String& path, const String& filename_template, FilenameConflicts conflicts) {
void export_image(const SetP& set, const vector<CardP>& cards, const String& path, const String& filename_template, FilenameConflicts conflicts)
{
wxBusyCursor busy;
// Script
ScriptP filename_script = parse(filename_template, nullptr, true);
+80 -84
View File
@@ -13,7 +13,6 @@
#include <boost/json.hpp>
#include <wx/filename.h>
#include <fstream>
#include <filesystem>
// ----------------------------------------------------------------------------- : Crop Rect Encoding
@@ -37,44 +36,44 @@ inline static String encodeRectInWxString(RealRect rect, int degrees) {
_("</mse-crop-data>");
}
/// Retreive a rect encoded in a string, return true if "<mse-crop-data>" was found
/// Retreive a rect encoded in a string, return true if successful
inline static bool decodeRectFromString(const String& rectString, RealRect& rect_out, int& degrees_out) {
size_t start = rectString.find(_("<mse-crop-data>"));
if (start == String::npos) return false;
size_t end = rectString.find(_("</mse-crop-data>"), start + 15);
if (end == String::npos) return true;
if (end == String::npos) return false;
String string = rectString.substr(start + 15, end - (start + 15));
if (string.empty()) return true;
if (string.empty()) return false;
size_t divider = string.find(_(";"));
if (divider == String::npos) return true;
if (divider == 0) return true;
if (divider == String::npos) return false;
if (divider == 0) return false;
int x;
if(!string.substr(0, divider).ToInt(&x)) return true;
if(!string.substr(0, divider).ToInt(&x)) return false;
string = string.substr(divider + 1);
divider = string.find(_(";"));
if (divider == String::npos) return true;
if (divider == 0) return true;
if (divider == String::npos) return false;
if (divider == 0) return false;
int y;
if(!string.substr(0, divider).ToInt(&y)) return true;
if(!string.substr(0, divider).ToInt(&y)) return false;
string = string.substr(divider + 1);
divider = string.find(_(";"));
if (divider == String::npos) return true;
if (divider == 0) return true;
if (divider == String::npos) return false;
if (divider == 0) return false;
int width;
if(!string.substr(0, divider).ToInt(&width)) return true;
if(!string.substr(0, divider).ToInt(&width)) return false;
string = string.substr(divider + 1);
divider = string.find(_(";"));
if (divider == String::npos) return true;
if (divider == 0) return true;
if (divider == String::npos) return false;
if (divider == 0) return false;
int height;
if(!string.substr(0, divider).ToInt(&height)) return true;
if(!string.substr(0, divider).ToInt(&height)) return false;
string = string.substr(divider + 1);
if(!string.ToInt(&degrees_out)) return true;
if(!string.ToInt(&degrees_out)) return false;
rect_out = RealRect(x, y, width, height);
return true;
@@ -82,18 +81,17 @@ inline static bool decodeRectFromString(const String& rectString, RealRect& rect
/// Retreive a rect encoded in a string, apply a transformation, then encode it back
inline static String transformEncodedRect(const String& rectString, RectTransform transform, double param_x, double param_y, int mode) {
RealRect rect(0.0, 0.0, 0.0, 0.0);
int degrees = 0;
decodeRectFromString(rectString, rect, degrees);
if (rect.width > 0.0 && rect.height > 0.0) {
transform(rect, degrees, param_x, param_y, mode);
return encodeRectInWxString(rect, degrees);
}
return _("");
RealRect rect(0,0,0,0);
int degrees;
if (!decodeRectFromString(rectString, rect, degrees)) return _("");
transform(rect, degrees, param_x, param_y, mode);
return encodeRectInWxString(rect, degrees);
}
/// Retreive all rects encoded in a string, apply a transformation, then encode them back
inline static String transformAllEncodedRects(const String& rectString, RectTransform transform, double param_x, double param_y, int mode = 0) {
RealRect rect(0,0,0,0);
int degrees;
size_t start = rectString.find(_("<mse-crop-data>"));
if (start == String::npos) return rectString;
size_t end = 0;
@@ -112,70 +110,67 @@ inline static String transformAllEncodedRects(const String& rectString, RectTran
// ----------------------------------------------------------------------------- : File to UTF8 Encoding
inline static const char Base64Alphabet[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
inline static const std::vector<int> Base64ReverseAlphabet = [] {
std::vector<int> table(256, -1);
for (int i = 0; i < 64; i++) table[(uint8_t)Base64Alphabet[i]] = i;
return table;
}();
/// Encode a file in a string
inline static std::string fileToUTF8(const std::string& filepath) {
// Load file
// File to char
std::ifstream file(filepath, std::ios::binary);
if (!file) {
queue_message(MESSAGE_WARNING, _("Could not find file: ") + String(filepath));
file.unsetf(std::ios::skipws);
std::vector<unsigned char> buffer = std::vector<unsigned char>(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
int size = buffer.size();
if (size < 2) {
queue_message(MESSAGE_WARNING, _("File too small to encode"));
return "";
}
size_t size = std::filesystem::file_size(filepath);
std::vector<uint8_t> data(size);
file.read(reinterpret_cast<char*>(data.data()), size);
// Base64 encode
std::string out;
out.reserve(((size + 2) / 3) * 4);
int val = 0;
int valb = -6;
for (uint8_t c : data) {
val = (val << 8) | c;
valb += 8;
while (valb >= 0) {
out.push_back(Base64Alphabet[(val >> valb) & 0x3F]);
valb -= 6;
// All bytes that have a highest bit of 0 are valid UTF8 characters, so:
// Reset the highest bit of each byte, store these bits in additional bytes at the end
const unsigned char highest_bit = 1 << 7;
unsigned char added_byte = 0;
for (int i = 0, b = 0 ; i < size ; ++i, ++b) {
if (b == 7) { // Never set the highest bit of the added byte
buffer.push_back(added_byte);
b = 0;
}
unsigned char bit = 1 << b;
if ((buffer[i] & highest_bit) != 0) { // The highest bit of the buffer is set
buffer[i] &= ~highest_bit; // Reset the highest bit of the buffer
added_byte |= bit; // Set the bit of the added byte
} else {
added_byte &= ~bit; // Reset the bit of the added byte
}
}
if (valb > -6) {
out.push_back(Base64Alphabet[((val << 8) >> (valb + 8)) & 0x3F]);
}
// Pad
while (out.size() % 4) {
out.push_back('=');
}
return out;
buffer.push_back(added_byte);
// Char to string
return std::string(buffer.begin(), buffer.end());
}
/// Retreive a file encoded in a string, return true if successful
inline static bool UTF8ToFile(const std::string& filepath, std::string& data) {
// Base64 decode
std::string out;
out.reserve(data.size() * 3 / 4);
int val = 0;
int valb = -8;
for (uint8_t c : data) {
if (c == '=') break; // padding, we're done
val = (val << 6) | Base64ReverseAlphabet[c];
valb += 6;
if (valb >= 0) {
out.push_back(static_cast<char>((val >> valb) & 0xFF));
valb -= 8;
inline static bool UTF8ToFile(const std::string& filepath, std::string& string) {
// String to char
std::vector<unsigned char> buffer(string.begin(), string.end());
int size = buffer.size();
if (size < 2) {
queue_message(MESSAGE_WARNING, _("File too small to decode"));
return false;
}
// Restore the highest bit of each byte
size = (size * 7) / 8;
const unsigned char highest_bit = 1 << 7;
unsigned char added_byte = buffer[size];
for (int i = 0, j = size, b = 0 ; i < size ; ++i, ++b) {
if (b == 7) {
++j;
added_byte = buffer[j];
b = 0;
}
unsigned char bit = 1 << b;
if ((added_byte & bit) != 0) { // The bit of the added byte is set
buffer[i] |= highest_bit; // Set the highest bit of the buffer
}
}
// Save file
std::ofstream file(filepath, std::ios::binary);
file.write(out.data(), out.size());
buffer.resize(size);
// Char to file
std::ofstream file(filepath, std::ios::out|std::ios::binary);
std::copy(buffer.cbegin(), buffer.cend(), std::ostream_iterator<unsigned char>(file));
return true;
}
@@ -189,21 +184,22 @@ inline static std::string encodeImageInString(const Image& img) {
return s;
}
/// Retreive an image encoded in a string, return true if "<mse-image-data>" was found
inline static bool decodeImageFromString(const String& string, Image& img_out) {
/// Retreive an image encoded in a string
inline static Image decodeImageFromString(const String& string) {
Image img;
size_t first = string.find(_("<mse-image-data>"));
if (first == String::npos) return false;
if (first == String::npos) return img;
size_t last = string.find(_("</mse-image-data>"), first + 16);
if (last == String::npos) return true;
if (last == String::npos) return img;
std::string s = string.substr(first + 16, last - (first + 16)).ToStdString();
if (s.empty()) return true;
if (s.empty()) return img;
const std::string& temppath = (wxFileName::CreateTempFileName(_("mse")) + _(".png")).ToStdString();
UTF8ToFile(temppath, s);
img_out.LoadFile(temppath, wxBITMAP_TYPE_PNG);
img.LoadFile(temppath, wxBITMAP_TYPE_PNG);
wxRemoveFile(temppath);
wxRemoveFile(temppath.substr(0, temppath.size() - 4));
return true;
return img;
}
// ----------------------------------------------------------------------------- : Metadata manipulation
+3 -8
View File
@@ -16,7 +16,6 @@
#include <data/pack.hpp>
#include <data/word_list.hpp>
#include <data/add_cards_script.hpp>
#include <data/update_cards_script.hpp>
#include <util/io/package_manager.hpp>
#include <script/script.hpp>
@@ -56,6 +55,7 @@ IMPLEMENT_REFLECTION(Game) {
REFLECT_NO_SCRIPT(json_paths);
REFLECT_NO_SCRIPT(statistics_dimensions);
REFLECT_NO_SCRIPT(statistics_categories);
REFLECT_COMPAT(<308, "pack_item", pack_types);
REFLECT_NO_SCRIPT(pack_types);
REFLECT_NO_SCRIPT(keyword_match_script);
REFLECT(has_keywords);
@@ -63,8 +63,7 @@ IMPLEMENT_REFLECTION(Game) {
REFLECT(keyword_parameter_types);
REFLECT_NO_SCRIPT(keywords);
REFLECT_NO_SCRIPT(word_lists);
REFLECT_NO_SCRIPT(add_cards_scripts);
REFLECT_NO_SCRIPT(update_cards_scripts);
REFLECT_NO_SCRIPT(add_cards_scripts);
REFLECT_NO_SCRIPT(auto_replaces);
}
@@ -206,11 +205,7 @@ void Game::validate(Version v) {
}
card_links_alt_names.emplace(linked_tr, linked_default);
}
}
// sort the update_cards_scripts from oldest to newest
std::sort(update_cards_scripts.begin(), update_cards_scripts.end(), [](const auto& a, const auto& b) {
return *a < *b;
});
}
}
void Game::initCardListColorScript() {
+21 -23
View File
@@ -26,7 +26,6 @@ DECLARE_POINTER_TYPE(KeywordMode);
DECLARE_POINTER_TYPE(Keyword);
DECLARE_POINTER_TYPE(WordList);
DECLARE_POINTER_TYPE(AddCardsScript);
DECLARE_POINTER_TYPE(UpdateCardsScript);
DECLARE_POINTER_TYPE(AutoReplace);
// ----------------------------------------------------------------------------- : Game
@@ -39,28 +38,27 @@ class Game : public Packaged {
public:
Game();
OptionalScript init_script; ///< Script of variables available to other scripts in this game
vector<FieldP> set_fields; ///< Fields for set information
IndexMap<FieldP,StyleP> default_set_style; ///< Default style for the set fields, because it is often the same
vector<FieldP> card_fields; ///< Fields on each card
vector<CardLinkP> card_links; ///< Possible links between cards
OptionalScript card_list_color_script; ///< Script that determines the color of items in the card list
OptionalScript import_script; ///< Script applied as the last step of the new_card function
vector<String> json_paths; ///< Paths inside JSON files to find the card array
vector<StatsDimensionP> statistics_dimensions; ///< (Additional) statistics dimensions
vector<StatsCategoryP> statistics_categories; ///< (Additional) statistics categories
vector<PackTypeP> pack_types; ///< Types of random card packs to generate
vector<WordListP> word_lists; ///< Word lists for editing with a drop down list
vector<AddCardsScriptP> add_cards_scripts; ///< Scripts for adding multiple cards to the set
vector<UpdateCardsScriptP> update_cards_scripts; ///< Scripts for updating cards made with an earlier version of this game
vector<AutoReplaceP> auto_replaces; ///< Things to autoreplace in textboxes
map<String,String> card_fields_alt_names; ///< Other names that fields might go by, for example in CSV files
map<String,String> card_links_alt_names; ///< Localized names that card links go by
bool has_keywords; ///< Does this game use keywords?
OptionalScript keyword_match_script; ///< For the keyword editor
vector<KeywordParamP> keyword_parameter_types;///< Types of keyword parameters
vector<KeywordModeP> keyword_modes; ///< Modes of keywords
vector<KeywordP> keywords; ///< Keywords for use in text
OptionalScript init_script; ///< Script of variables available to other scripts in this game
vector<FieldP> set_fields; ///< Fields for set information
IndexMap<FieldP,StyleP> default_set_style; ///< Default style for the set fields, because it is often the same
vector<FieldP> card_fields; ///< Fields on each card
vector<CardLinkP> card_links; ///< Possible links between cards
OptionalScript card_list_color_script; ///< Script that determines the color of items in the card list
OptionalScript import_script; ///< Script applied as the last step of the new_card function
vector<String> json_paths; ///< Paths inside JSON files to find the card array
vector<StatsDimensionP> statistics_dimensions; ///< (Additional) statistics dimensions
vector<StatsCategoryP> statistics_categories; ///< (Additional) statistics categories
vector<PackTypeP> pack_types; ///< Types of random card packs to generate
vector<WordListP> word_lists; ///< Word lists for editing with a drop down list
vector<AddCardsScriptP> add_cards_scripts; ///< Scripts for adding multiple cards to the set
vector<AutoReplaceP> auto_replaces; ///< Things to autoreplace in textboxes
map<String,String> card_fields_alt_names; ///< Other names that fields might go by, for example in CSV files
map<String,String> card_links_alt_names; ///< Localized names that card links go by
bool has_keywords; ///< Does this game use keywords?
OptionalScript keyword_match_script; ///< For the keyword editor
vector<KeywordParamP> keyword_parameter_types;///< Types of keyword parameters
vector<KeywordModeP> keyword_modes; ///< Modes of keywords
vector<KeywordP> keywords; ///< Keywords for use in text
Dependencies dependent_scripts_cards; ///< scripts that depend on the card list
Dependencies dependent_scripts_keywords; ///< scripts that depend on the keywords
+1
View File
@@ -85,6 +85,7 @@ bool Keyword::contains(QuickFilterPart const& query) const {
IMPLEMENT_REFLECTION(Keyword) {
REFLECT(keyword);
if (handler.formatVersion() < 301) read_compat(handler, this);
REFLECT(match);
REFLECT(reminder);
REFLECT(rules);
+9 -82
View File
@@ -14,7 +14,6 @@
#include <data/keyword.hpp>
#include <data/pack.hpp>
#include <data/field.hpp>
#include <data/update_cards_script.hpp>
#include <data/field/text.hpp> // for 0.2.7 fix
#include <data/field/information.hpp>
#include <data/field/image.hpp>
@@ -23,7 +22,6 @@
#include <util/tagged_string.hpp> // for 0.2.7 fix
#include <util/order_cache.hpp>
#include <util/delayed_index_maps.hpp>
#include <util/uid.hpp>
#include <script/script_manager.hpp>
#include <script/profiler.hpp>
#include <wx/sstream.h>
@@ -69,16 +67,6 @@ void Set::updateStyles(const CardP& card, bool only_content_dependent) {
void Set::updateDelayed() {
script_manager->updateDelayed();
}
void Set::buildUIDMap() {
card_uids.clear();
FOR_EACH(c, cards) {
while (card_uids.find(c->uid) != card_uids.end()) {
queue_message(MESSAGE_WARNING, _("Multiple cards found with same uid:\n") + c->identification() + _("\n") + card_uids[c->uid]->identification() + _("\nPlease notify someone on the Discord server."));
c->uid = generate_uid();
}
card_uids[c->uid] = c;
}
}
Context& Set::getContextForThumbnails() {
assert(!wxThread::IsMain());
@@ -173,7 +161,7 @@ void fix_value_207(const ValueP& value) {
void Set::validate(Version file_app_version) {
Packaged::validate(file_app_version);
// are the game and stylesheet defined?
// are the
if (!game) {
throw Error(_ERROR_1_("no game specified",_TYPE_("set")));
}
@@ -184,9 +172,7 @@ void Set::validate(Version file_app_version) {
if (stylesheet->game != game) {
throw Error(_ERROR_("stylesheet and set refer to different game"));
}
// We can probably retire this
/*
// This is our chance to fix version incompatabilities
if (file_app_version < 207) {
// Since 0.2.7 we use </tag> style close tags, in older versions it was </>
@@ -195,65 +181,14 @@ void Set::validate(Version file_app_version) {
FOR_EACH(v, c->data) fix_value_207(v);
}
FOR_EACH(v, data) fix_value_207(v);
FOR_EACH(s, styleData) {
/* FOR_EACH(s, styleData) {
FOR_EACH(v, s.second->data) fix_value_207(v);
}
}
*/
*/ }
// we want at least one card
if (cards.empty()) cards.push_back(make_intrusive<Card>(*game));
// 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
// then apply all the stylesheet scripts that are older than the second game script
// then apply the second game script, etc...
Version previous_cutoff = Version();
Version current_cutoff = Version();
for (size_t g = 0; g < game->update_cards_scripts.size() + 1; ++g) {
bool last_iteration = g == game->update_cards_scripts.size();
UpdateCardsScriptP game_script = last_iteration ? nullptr : game->update_cards_scripts[g];
previous_cutoff = current_cutoff;
current_cutoff = last_iteration ? current_cutoff : game_script->before_version;
// Apply stylesheet scripts that are older than the current game script
for (size_t i = 0; i < cards.size(); ++i) {
CardP& card = cards[i];
StyleSheetP stylesheet = card->stylesheet ? card->stylesheet : stylesheetForP(card);
Version stylesheet_version = card->stylesheet_version.isZero() ? this->stylesheet_version : card->stylesheet_version;
for (size_t j = 0; j < stylesheet->update_cards_scripts.size(); ++j) {
UpdateCardsScriptP& script = stylesheet->update_cards_scripts[j];
if (script->before_version >= current_cutoff && !last_iteration) continue;
if (script->before_version < previous_cutoff) continue;
if (stylesheet_version >= script->before_version) continue;
vector<CardP> new_cards = script->perform(*this, card);
if (!new_cards.empty()) {
FOR_EACH(new_card, new_cards) {
// Initialize the stylesheet_version if it wasn't defined, to prevent this script from applying again
if (stylesheet == stylesheetForP(new_card) && new_card->stylesheet_version < script->before_version) {
new_card->stylesheet_version = script->before_version;
}
}
--i;
break;
}
}
}
// Apply current game script
if (last_iteration || game_version >= current_cutoff) continue;
size_t size = cards.size();
for (int i = 0; i < size; ++i) {
CardP& card = cards[i];
vector<CardP> new_cards = game_script->perform(*this, card);
if (!new_cards.empty()) {
--i;
--size;
}
}
}
script_manager->updateAll();
}
void reflect_version_check(Reader& handler, const Char* key, intrusive_ptr<Packaged> const& package) {
@@ -277,23 +212,15 @@ IMPLEMENT_REFLECTION(Set) {
REFLECT_IF_READING {
data.init(game->set_fields);
}
if (Handler::isReading) {
REFLECT_NO_SCRIPT(game_version);
}
else {
reflect_version_check(handler, _("game_version"), game);
}
reflect_version_check(handler, _("game_version"), game);
WITH_DYNAMIC_ARG(game_for_reading, game.get());
REFLECT(stylesheet);
if (Handler::isReading) {
REFLECT_NO_SCRIPT(stylesheet_version);
}
else {
reflect_version_check(handler, _("stylesheet_version"), stylesheet);
}
REFLECT_COMPAT(<300, "style", stylesheet);
reflect_version_check(handler, _("stylesheet_version"), stylesheet);
WITH_DYNAMIC_ARG(stylesheet_for_reading, stylesheet.get());
REFLECT_N("set_info", data);
if (stylesheet) {
REFLECT_COMPAT(<300, "extra_set_info", styling_data);
REFLECT_N("styling", styling_data);
}
// Experimental: save each card to a different file
+11 -18
View File
@@ -45,27 +45,22 @@ public:
Set(const StyleSheetP& stylesheet);
~Set();
GameP game; ///< The game this set uses
StyleSheetP stylesheet; ///< The default stylesheet
GameP game; ///< The game this set uses
StyleSheetP stylesheet; ///< The default stylesheet
/// The values on the fields of the set
/** The indices should correspond to the set_fields in the Game */
IndexMap<FieldP, ValueP> data;
IndexMap<FieldP, ValueP> data;
/// Extra values for specific stylesheets, indexed by stylesheet name
DelayedIndexMaps<FieldP,ValueP> styling_data;
vector<CardP> cards; ///< The cards in the set
unordered_map<String, CardP> card_uids; ///< The uids of the cards in the set
vector<KeywordP> keywords; ///< Additional keywords used in this set
vector<PackTypeP> pack_types; ///< Additional/replacement pack types
String apprentice_code; ///< Code to use for apprentice (magic only)
ActionStack actions; ///< Actions performed on this set and the cards in it
KeywordDatabase keyword_db; ///< Database for matching keywords, must be cleared when keywords change
VCSP vcs; ///< The version control system to use
/// What version of the game was this set using when it was last saved?
Version game_version;
/// What version of the default stylesheet was this set using when it was last saved?
Version stylesheet_version;
vector<CardP> cards; ///< The cards in the set
vector<KeywordP> keywords; ///< Additional keywords used in this set
vector<PackTypeP> pack_types; ///< Additional/replacement pack types
String apprentice_code; ///< Code to use for apprentice (magic only)
ActionStack actions; ///< Actions performed on this set and the cards in it
KeywordDatabase keyword_db; ///< Database for matching keywords, must be cleared when keywords change
VCSP vcs; ///< The version control system to use
/// A context for performing scripts
/** Should only be used from the main thread! */
Context& getContext();
@@ -76,8 +71,6 @@ public:
void updateStyles(const CardP& card, bool only_content_dependent);
/// Update scripts that were delayed
void updateDelayed();
/// Update uid map
void buildUIDMap();
/// A context for performing scripts
/** Should only be used from the thumbnail thread! */
Context& getContextForThumbnails();
+1 -7
View File
@@ -10,7 +10,6 @@
#include <data/stylesheet.hpp>
#include <data/game.hpp>
#include <data/field.hpp>
#include <data/update_cards_script.hpp>
#include <util/io/package_manager.hpp>
#include <gui/new_window.hpp> // for selecting stylesheets on load error
@@ -76,11 +75,7 @@ void StyleSheet::validate(Version ver) {
throw Error(_ERROR_1_("no game specified",_TYPE_("stylesheet")));
}
// a stylesheet depends on the game it is made for
requireDependency(game.get());
// sort the update_cards_scripts from oldest to newest
std::sort(update_cards_scripts.begin(), update_cards_scripts.end(), [](const auto& a, const auto& b) {
return *a < *b;
});
requireDependency(game.get());
}
@@ -130,7 +125,6 @@ IMPLEMENT_REFLECTION(StyleSheet) {
extra_card_style.init(extra_card_fields);
}
REFLECT(extra_card_style);
REFLECT_NO_SCRIPT(update_cards_scripts);
}
+6 -8
View File
@@ -22,7 +22,6 @@ DECLARE_POINTER_TYPE(StyleSheet);
DECLARE_POINTER_TYPE(Field);
DECLARE_POINTER_TYPE(Style);
DECLARE_POINTER_TYPE(CardRegion);
DECLARE_POINTER_TYPE(UpdateCardsScript);
// ----------------------------------------------------------------------------- : StyleSheet
@@ -34,13 +33,12 @@ class StyleSheet : public Packaged {
public:
StyleSheet();
GameP game; ///< The game this stylesheet is made for
OptionalScript init_script; ///< Script of variables available to other scripts in this stylesheet
vector<UpdateCardsScriptP> update_cards_scripts; ///< Scripts for updating cards made with an earlier version of this stylesheet
double card_width; ///< The width of a card in pixels
double card_height; ///< The height of a card in pixels
double card_dpi; ///< The resolution of a card in dots per inch
Color card_background; ///< The background color of cards
GameP game; ///< The game this stylesheet is made for
OptionalScript init_script; ///< Script of variables available to other scripts in this stylesheet
double card_width; ///< The width of a card in pixels
double card_height; ///< The height of a card in pixels
double card_dpi; ///< The resolution of a card in dots per inch
Color card_background; ///< The background color of cards
vector<CardRegionP> card_regions;
/// The styling for card fields
/** The indices should correspond to the card_fields in the Game */
+1
View File
@@ -178,6 +178,7 @@ IMPLEMENT_REFLECTION(SymbolInFont) {
REFLECT(draw_text);
REFLECT(text_font);
REFLECT(text_alignment);
REFLECT_COMPAT(<300,"text_align",text_alignment);
REFLECT(text_margin_left);
REFLECT(text_margin_right);
REFLECT(text_margin_top);
-57
View File
@@ -1,57 +0,0 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make card games |
//| Copyright: (C) Twan van Laarhoven and the other MSE developers |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <data/update_cards_script.hpp>
#include <data/action/set.hpp>
#include <data/set.hpp>
#include <data/card.hpp>
#include <data/stylesheet.hpp>
#include <data/action/value.hpp>
// ----------------------------------------------------------------------------- : UpdateCardsScript
IMPLEMENT_REFLECTION_NO_SCRIPT(UpdateCardsScript) {
REFLECT(before_version);
REFLECT(description);
REFLECT(enabled);
REFLECT(script);
}
void UpdateCardsScript::perform(Set& set, CardP& card, vector<CardP>& out) {
// Perform script
Context& ctx = set.getContext(card);
if (enabled.hasBeenRead()) {
enabled.update(ctx);
if (!enabled()) return;
}
ScriptValueP result = script.invoke(ctx);
// Add cards to out
ScriptValueP it = result->makeIterator();
while (ScriptValueP item = it->next()) {
CardP new_card = from_script<CardP>(item);
// is this a new card?
if (contains(set.cards,new_card) || contains(out,new_card)) {
// make copy
new_card = make_intrusive<Card>(&set, new_card);
}
out.push_back(new_card);
}
}
vector<CardP> UpdateCardsScript::perform(Set& set, CardP card) {
// Perform script
vector<CardP> cards;
perform(set, card, cards);
// Add to set
if (!cards.empty()) {
set.actions.addAction(make_unique<UpdateCardAction>(set, cards, vector<CardP>{card}), false);
}
return cards;
}
-39
View File
@@ -1,39 +0,0 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make card games |
//| Copyright: (C) Twan van Laarhoven and the other MSE developers |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#pragma once
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <script/scriptable.hpp>
class Set;
DECLARE_POINTER_TYPE(Card);
// ----------------------------------------------------------------------------- : UpdateCardsScript
/// A script to add one or more cards to a set
class UpdateCardsScript : public IntrusivePtrBase<UpdateCardsScript> {
public:
Version before_version;
String description;
Scriptable<bool> enabled;
OptionalScript script;
bool operator < (const UpdateCardsScript& other) const {
return before_version < other.before_version;
}
/// Perform the script; return the cards (if any)
void perform(Set& set, CardP& card, vector<CardP>& out);
/// Perform the script; add cards to the set
vector<CardP> perform(Set& set, CardP card); // don't use CardP& here, because set.cards may get reallocated which would invalidate the ref
DECLARE_REFLECTION();
};
+17 -33
View File
@@ -19,7 +19,7 @@ template <typename T> inline T sqr(T x) { return x * x; }
void linear_blend(Image& img1, const Image& img2, double x1,double y1, double x2,double y2) {
int width = img1.GetWidth(), height = img1.GetHeight();
if (img2.GetWidth() != width || img2.GetHeight() != height) {
throw Error(_ERROR_3_("blending different sizes", "linear_blend", String()<<width<<_("x")<<height, String()<<img2.GetWidth()<<_("x")<<img2.GetHeight()));
throw Error(_ERROR_1_("blending different sizes", "linear_blend"));
}
const int fixed = 1<<16; // fixed point multiplier
@@ -82,10 +82,10 @@ void linear_blend(Image& img1, const Image& img2, double x1,double y1, double x2
void mask_blend(Image& img1, const Image& img2, const Image& mask) {
int width = img1.GetWidth(), height = img1.GetHeight();
if (img2.GetWidth() != width || img2.GetHeight() != height) {
throw Error(_ERROR_3_("blending different sizes", "masked_blend", String()<<width<<_("x")<<height, String()<<img2.GetWidth()<<_("x")<<img2.GetHeight()));
throw Error(_("Images used for blending in masked_blend function must have the same size"));
}
if (mask.GetWidth() != width || mask.GetHeight() != height) {
throw Error(_ERROR_3_("blending different mask", "masked_blend", String()<<width<<_("x")<<height, String()<<mask.GetWidth()<<_("x")<<mask.GetHeight()));
throw Error(_("Mask used for blending in masked_blend function must have the same size as the images"));
}
UInt size = width * height;
@@ -124,49 +124,33 @@ void set_alpha(Image& img, const Image& img_alpha) {
}
void set_alpha(Image& img, Byte* al, const wxSize& alpha_size) {
int width = img.GetWidth(), height = img.GetHeight();
if (width != alpha_size.GetWidth() || height != alpha_size.GetHeight()) {
throw Error(_ERROR_3_("blending different mask", "set_alpha", String()<<width<<_("x")<<height, String()<<alpha_size.GetWidth()<<_("x")<<alpha_size.GetHeight()));
if (img.GetWidth() != alpha_size.GetWidth() || img.GetHeight() != alpha_size.GetHeight()) {
throw Error(_("Image must have same size as mask"));
}
if (!img.HasAlpha()) {
// copy
img.InitAlpha();
memcpy(img.GetAlpha(), al, width * height);
memcpy(img.GetAlpha(), al, img.GetWidth() * img.GetHeight());
} else{
// merge
Byte *im = img.GetAlpha();
size_t size = width * height;
size_t size = img.GetWidth() * img.GetHeight();
for (size_t i = 0 ; i < size ; ++i) {
im[i] = (im[i] * al[i]) / 255;
}
}
}
void set_alpha(Image& img, double alpha) {
size_t size = img.GetWidth() * img.GetHeight();
if (alpha <= 0.0) {
if (!img.HasAlpha()) img.InitAlpha();
memset(img.GetAlpha(), Byte(0), size);
}
else if (alpha > 1.0) {
if (!img.HasAlpha()) return;
else {
Byte *im = img.GetAlpha();
for (size_t i = 0 ; i < size ; ++i) {
im[i] = Byte(min(im[i] * alpha, 255.0));
}
}
}
else {
Byte b_alpha = Byte(alpha * 255);
if (!img.HasAlpha()) {
img.InitAlpha();
memset(img.GetAlpha(), b_alpha, size);
} else {
Byte *im = img.GetAlpha();
for (size_t i = 0 ; i < size ; ++i) {
im[i] = (im[i] * b_alpha) / 255;
}
void set_alpha(Image& img, double alpha) {
Byte b_alpha = Byte(alpha * 255);
if (!img.HasAlpha()) {
img.InitAlpha();
memset(img.GetAlpha(), b_alpha, img.GetWidth() * img.GetHeight());
} else {
Byte *im = img.GetAlpha();
size_t size = img.GetWidth() * img.GetHeight();
for (size_t i = 0 ; i < size ; ++i) {
im[i] = (im[i] * b_alpha) / 255;
}
}
}
+3 -4
View File
@@ -449,14 +449,13 @@ void combine_image_do(Image& a, Image b) {
void combine_image(Image& a, const Image& b, ImageCombine combine) {
// Images must have same size
int width = a.GetWidth(), height = a.GetHeight();
if (b.GetWidth() != width || b.GetHeight() != height) {
throw Error(_ERROR_3_("blending different sizes", "combine_blend", String()<<width<<_("x")<<height, String()<<b.GetWidth()<<_("x")<<b.GetHeight()));
if (a.GetWidth() != b.GetWidth() || a.GetHeight() != b.GetHeight()) {
throw Error(_ERROR_1_("blending different sizes", "combine_blend"));
}
// Copy alpha channel?
if (b.HasAlpha()) {
if (!a.HasAlpha()) a.InitAlpha();
memcpy(a.GetAlpha(), b.GetAlpha(), width * height);
memcpy(a.GetAlpha(), b.GetAlpha(), a.GetWidth() * a.GetHeight());
}
// Combine image data, by dispatching to combineImageDo
switch(combine) {
+35 -55
View File
@@ -783,57 +783,32 @@ bool SetMetadataImage::operator == (const GeneratedImage& that) const {
&& metadata == that2->metadata;
}
// ----------------------------------------------------------------------------- : ScriptedImage
ScriptedImage::ScriptedImage(Set* set, const GeneratedImageP& image) {
// get the image
Image img = image->generate(GeneratedImage::Options(0, 0, set, set));
// add the file to the set
LocalFileName new_image_file = set->newFileName(_("scripted_image"), _(".png"));
savename = new_image_file.toStringForWriting();
loadpath = savename;
img.SaveFile(set->nameOut(new_image_file), wxBITMAP_TYPE_PNG);
}
Image ScriptedImage::generate(const Options& opt) {
auto imageInputStream = opt.local_package->openIn(savename);
Image img(*imageInputStream, wxBITMAP_TYPE_PNG);
if (!img.IsOk()) throw ScriptError(_ERROR_1_("can't import image", loadpath));
return img;
}
bool ScriptedImage::operator == (const GeneratedImage& that) const {
const ScriptedImage* that2 = dynamic_cast<const ScriptedImage*>(&that);
return that2 && that2->loadpath == loadpath;
}
// ----------------------------------------------------------------------------- : ImportedImage
ImportedImage::ImportedImage(Set* set, const String& filepath) {
// determine save name
ImportedImage::ImportedImage(Set* set, const String& filepath)
{
loadpath = filepath;
savename = normalize_internal_filename(loadpath);
savename.Replace(":", "-");
savename.Replace("/", "-");
// has the set already been saved at least once?
if (set->needSaveAs()) throw ScriptError(_ERROR_1_("can't import image without set", loadpath));
// does the file pointed to by filepath exist?
if (!wxFileName(loadpath, wxPATH_UNIX).FileExists()) {
if (set->contains(savename)) return;
else throw ScriptError(_ERROR_1_("import not found", loadpath));
}
if (!wxFileName(loadpath, wxPATH_UNIX).FileExists()) throw ScriptError(_ERROR_1_("import not found", loadpath));
// is the file an image?
Image img;
img.LoadFile(loadpath);
if (!img.IsOk()) throw ScriptError(_ERROR_1_("import not image", loadpath));
// add the file to the set
LocalFileName new_image_file = set->newFileName(savename, _(".png"));
savename = new_image_file.toStringForWriting();
img.SaveFile(set->nameOut(new_image_file), wxBITMAP_TYPE_PNG);
// add the file to the set (or overwrite it if pre-existing), save set
savename = normalize_internal_filename(loadpath + _(".png"));
savename.Replace(":", "-");
savename.Replace("/", "-");
auto outStream = set->openOut(savename);
img.SaveFile(*outStream, wxBITMAP_TYPE_PNG);
if (!outStream->IsOk()) throw ScriptError(_ERROR_1_("can't write image to set", loadpath));
outStream->Close();
set->save(false);
}
Image ImportedImage::generate(const Options& opt) {
@@ -852,27 +827,32 @@ bool ImportedImage::operator == (const GeneratedImage& that) const {
// ----------------------------------------------------------------------------- : DownloadedImage
DownloadedImage::DownloadedImage(Set* set, const String& url) {
// determine save name
DownloadedImage::DownloadedImage(Set* set, const String& url)
{
loadpath = url;
savename = normalize_internal_filename(loadpath);
savename.Replace(":", "-");
savename.Replace("/", "-");
// has the set already been saved at least once?
if (set->needSaveAs()) throw ScriptError(_ERROR_1_("can't download image without set", loadpath));
// can we download the data?
WebRequestWindow wnd(loadpath);
if (wnd.ShowModal() != wxID_OK) {
if (set->contains(savename)) return;
else throw ScriptError(_ERROR_1_("can't download image", loadpath));
}
if (wnd.ShowModal() != wxID_OK) throw ScriptError(_ERROR_1_("can't download image", loadpath));
// is the data an image?
if (!wnd.content_type.StartsWith(_("image/"))) throw ScriptError(_ERROR_1_("download not image", loadpath));
// add the file to the set
LocalFileName new_image_file = set->newFileName(savename, _(".png"));
savename = new_image_file.toStringForWriting();
wnd.image_out.SaveFile(set->nameOut(new_image_file), wxBITMAP_TYPE_PNG);
const String& content_type = wnd.out.GetContentType();
if (!content_type.StartsWith(_("image"))) throw ScriptError(_ERROR_1_("download not image", loadpath));
Image img(*wnd.out.GetStream());
if (!img.IsOk()) throw ScriptError(_ERROR_("web request corrupted"));
// add the file to the set (or overwrite it if pre-existing), save set
savename = normalize_internal_filename(loadpath + _(".png"));
savename.Replace(":", "-");
savename.Replace("/", "-");
auto outStream = set->openOut(savename);
img.SaveFile(*outStream, wxBITMAP_TYPE_PNG);
if (!outStream->IsOk()) throw ScriptError(_ERROR_1_("can't write image to set", loadpath));
outStream->Close();
set->save(false);
}
Image DownloadedImage::generate(const Options& opt) {
-10
View File
@@ -522,16 +522,6 @@ protected:
String savename;
};
// ----------------------------------------------------------------------------- : ScriptedImage
/// Load an image from a script
class ScriptedImage : public ExternalImage {
public:
ScriptedImage(Set* set, const GeneratedImageP& image);
Image generate(const Options&) override;
bool operator == (const GeneratedImage& that) const override;
};
// ----------------------------------------------------------------------------- : ImportedImage
/// Load an image from the filesystem
+2 -1
View File
@@ -40,7 +40,8 @@ const char* MSE_AUTHORS[] = {
"Olivier Bocksberger (G-e-n-e-v-e-n-s-i-S)",
"Brendan Hagan (haganbmj)",
"Thomas Tkacz (TomTkacz)",
"CaiCai (247321453)"
"CaiCai (247321453)",
"Amy Markey (amyinspace)"
};
void AboutWindow::draw(DC& dc) {
+6 -2
View File
@@ -126,7 +126,11 @@ void CardLinkWindow::onOk(wxCommandEvent&) {
linked_uids.push_back(linked_cards[i]->uid);
}
// Find free links
vector<int> free_link_indexes = selected_card->findFreeLinks(linked_uids, set->card_uids);
unordered_set<String> all_existing_uids;
FOR_EACH(card, set->cards) {
all_existing_uids.insert(card->uid);
}
vector<int> free_link_indexes = selected_card->findFreeLinks(linked_uids, all_existing_uids);
int free_link_count = 0;
for (size_t i = 0; i < free_link_indexes.size(); ++i) {
if (free_link_indexes[i] >= 0) free_link_count++;
@@ -159,7 +163,7 @@ void CardLinkWindow::onOk(wxCommandEvent&) {
// Find reciprocal free slots and make actions
String& selected_uid = selected_card->uid;
for (size_t i = 0; i < linked_cards.size(); ++i) {
int free_link_index = linked_cards[i]->findFreeLink(selected_uid, set->card_uids);
int free_link_index = linked_cards[i]->findFreeLink(selected_uid, all_existing_uids);
if (free_link_index >= 0) {
actions.push_back(make_intrusive<OneWayLinkCardsAction>(linked_cards[i], selected_uid, selected_relation_string, free_link_index));
}
+108 -212
View File
@@ -165,8 +165,7 @@ bool CardListBase::doCopy() {
if (cards_to_copy.empty()) return false;
// put on clipboard
if (!wxTheClipboard->Open()) return false;
bool ok = wxTheClipboard->SetData(new CardsOnClipboard(set, _(""), cards_to_copy)); // ignore result
wxTheClipboard->Flush();
bool ok = wxTheClipboard->SetData(new CardsOnClipboard(set, _(""), cards_to_copy)); // ignore result
wxTheClipboard->Close();
return ok;
}
@@ -192,8 +191,7 @@ bool CardListBase::doCopyCardAndLinkedCards() {
}
}
}
bool ok = wxTheClipboard->SetData(new CardsOnClipboard(set, _(""), cards_to_copy)); // ignore result
wxTheClipboard->Flush();
bool ok = wxTheClipboard->SetData(new CardsOnClipboard(set, _(""), cards_to_copy)); // ignore result
wxTheClipboard->Close();
return ok;
}
@@ -201,8 +199,7 @@ bool CardListBase::doCopyCardAndLinkedCards() {
bool CardListBase::doPaste() {
if (!canPaste()) return false;
if (!wxTheClipboard->Open()) return false;
bool ok = wxTheClipboard->GetData(*drop_target->data_object);
wxTheClipboard->Flush();
bool ok = wxTheClipboard->GetData(*drop_target->data_object);
wxTheClipboard->Close();
if (ok) return parseData(false);
return false;
@@ -212,15 +209,9 @@ bool CardListBase::doDelete() {
// cards to delete
vector<CardP> cards_to_delete;
getSelection(cards_to_delete);
if (cards_to_delete.empty()) return false;
// if there is one double faced card, select the other face to make it clear it hasn't been deleted
CardP other_face = nullptr;
if (cards_to_delete.size() == 1) {
other_face = cards_to_delete[0]->getLinkedOtherFaceCard(*set);
}
if (cards_to_delete.empty()) return false;
// delete cards
set->actions.addAction(make_unique<AddCardAction>(REMOVE, *set, cards_to_delete));
if (other_face) setCard(other_face, true);
set->actions.addAction(make_unique<AddCardAction>(REMOVE, *set, cards_to_delete));
return true;
}
@@ -251,65 +242,66 @@ bool CardListBase::doBulkModification() {
return false;
}
void CardListBase::parseImageMetadata(CardP& card, const Image& image) {
void CardListBase::parseImageMetadata(CardP& card, const Image& image)
{
for (IndexMap<FieldP, ValueP>::iterator it = card->data.begin(); it != card->data.end(); it++) {
ImageValue* value = dynamic_cast<ImageValue*>(it->get());
if (value && !value->filename.empty()) {
RealRect rect(0.0, 0.0, 0.0, 0.0);
int degrees = 0;
if (decodeRectFromString(value->filename.toStringForKey(), rect, degrees)) {
rect = rect.intersect(RealRect(0.0, 0.0, image.GetWidth(), image.GetHeight()));
if (rect.width > 0.0 && rect.height > 0.0) {
Image img = image.GetSubImage(rect);
img = rotate_image(img, deg_to_rad(360 - degrees));
LocalFileName filename = set->newFileName(_("cropped_image"), _(".png")); // a new unique name in the package
img.SaveFile(set->nameOut(filename), wxBITMAP_TYPE_PNG);
value->filename = filename;
}
else {
value->filename = LocalFileName();
//queue_message(MESSAGE_WARNING, _("failed to recover image crop for card '") + card->identification() + _("'"));
}
decodeRectFromString(value->filename.toStringForKey(), rect, degrees);
rect = rect.intersect(RealRect(0.0, 0.0, image.GetWidth(), image.GetHeight()));
if (rect.width > 0.0 && rect.height > 0.0) {
Image img = image.GetSubImage(rect);
img = rotate_image(img, deg_to_rad(360 - degrees));
LocalFileName filename = set->newFileName("cropped_image", _(".png")); // a new unique name in the package
img.SaveFile(set->nameOut(filename), wxBITMAP_TYPE_PNG);
value->filename = filename;
}
else {
value->filename = LocalFileName();
}
}
}
}
void CardListBase::parseImageMetadata(CardP& card) {
void CardListBase::parseImageMetadata(CardP& card)
{
for (IndexMap<FieldP, ValueP>::iterator it = card->data.begin(); it != card->data.end(); it++) {
ImageValue* value = dynamic_cast<ImageValue*>(it->get());
if (value && !value->filename.empty()) {
Image img;
if (decodeImageFromString(value->filename.toStringForKey(), img)) {
if (img.IsOk()) {
LocalFileName filename = set->newFileName(_("decoded_image"), _(".png")); // a new unique name in the package
img.SaveFile(set->nameOut(filename), wxBITMAP_TYPE_PNG);
value->filename = filename;
}
else {
value->filename = LocalFileName();
//queue_message(MESSAGE_WARNING, _("failed to recover image encode for card '") + card->identification() + _("'"));
}
if (value) {
Image img = decodeImageFromString(value->filename.toStringForKey());
if (img.IsOk()) {
LocalFileName filename = set->newFileName(_("decoded_image"), _(".png")); // a new unique name in the package
img.SaveFile(set->nameOut(filename), wxBITMAP_TYPE_PNG);
value->filename = filename;
}
}
}
}
bool CardListBase::parseUrl(String& url, vector<CardP>& out) {
bool CardListBase::parseUrl(String& url, vector<CardP>& out) {
size_t j = out.size();
size_t pos = url.find("URL=");
if (pos != std::string::npos) {
url = url.substr(pos+4);
}
if (!url.StartsWith(_("http"))) return false;
if (!url.StartsWith(_("http"))) return false;
WebRequestWindow wnd(url);
if (wnd.ShowModal() == wxID_OK) {
if (wnd.content_type.StartsWith(_("image/"))) {
parseImage(wnd.image_out, out);
if (wnd.ShowModal() == wxID_OK) {
const String& content_type = wnd.out.GetContentType();
if (content_type.StartsWith(_("image"))) {
Image img(*wnd.out.GetStream());
if (img.IsOk()) {
parseImage(img, out);
}
else {
queue_message(MESSAGE_ERROR, _ERROR_("web request corrupted"));
}
}
else if (wnd.content_type.StartsWith(_("text/"))) {
String text = String(wnd.text_out.data(), wnd.text_out.size());
else if (content_type.StartsWith(_("text"))) {
String text = wnd.out.AsString();
parseText(text, out);
}
else {
@@ -319,26 +311,19 @@ bool CardListBase::parseUrl(String& url, vector<CardP>& out) {
return j < out.size();
}
bool CardListBase::parseFiles(wxArrayString& filenames, vector<CardP>& out) {
bool CardListBase::parseFiles(wxArrayString& filenames, vector<CardP>& out) {
size_t j = out.size();
for (size_t i = 0; i < filenames.size(); i++) {
if (wxImage::CanRead(filenames[i])) {
// if it's an image file, try to get meta_data
Image image_file;
image_file.SetLoadFlags(image_file.GetLoadFlags() & ~wxImage::Load_Verbose);
if (image_file.LoadFile(filenames[i])) {
parseImage(image_file, out);
}
else queue_message(MESSAGE_ERROR, _ERROR_("can't load image"));
// if it's an image file, try to get meta_data
Image image_file;
image_file.SetLoadFlags(image_file.GetLoadFlags() & ~wxImage::Load_Verbose);
if (image_file.LoadFile(filenames[i])) {
parseImage(image_file, out);
} else {
// if it's an url, request the data
std::ifstream ifs(filenames[i].ToStdString());
if (ifs.bad() || ifs.fail() || !ifs.good() || !ifs.is_open()) continue;
std::string content((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
bool looks_like_text = std::all_of(content.begin(), content.end(), [](char c) {
return isprint(c) || isspace(c);
});
if (!looks_like_text) continue;
if (ifs.bad() || ifs.fail() || !ifs.good() || !ifs.is_open()) continue;
std::string content((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
wxString text(content);
if (!parseUrl(text, out)) parseText(text, out);
}
@@ -346,7 +331,7 @@ bool CardListBase::parseFiles(wxArrayString& filenames, vector<CardP>& out) {
return j < out.size();
}
bool CardListBase::parseImage(Image& image, vector<CardP>& out) {
bool CardListBase::parseImage(Image& image, vector<CardP>& out) {
size_t j = out.size();
if (image.HasOption(wxIMAGE_OPTION_PNG_DESCRIPTION)) {
auto text = image.GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION);
@@ -361,30 +346,26 @@ bool CardListBase::parseImage(Image& image, vector<CardP>& out) {
return j < out.size();
}
bool CardListBase::parseText(String& text, vector<CardP>& out) {
if (text.size() == 0) {
return false;
}
size_t j = out.size();
size_t pos = text.find("<mse-card-data>");
if (pos != wxString::npos) {
text = text.substr(pos + 15, text.find("</mse-card-data>") - pos - 15);
bool CardListBase::parseText(String& text, vector<CardP>& out) {
size_t j = out.size();
if (size_t pos = text.find("<mse-card-data>") != wxString::npos) {
text = text.substr(pos + 14, text.find("</mse-card-data>") - pos - 14);
}
try {
ScriptValueP sv = json_to_mse(text, set.get());
if (sv->type() == SCRIPT_COLLECTION) {
if (sv->type() == SCRIPT_COLLECTION) {
if (ScriptCustomCollection* custom = dynamic_cast<ScriptCustomCollection*>(sv.get())) {
for (size_t i = 0; i < custom->value.size(); i++) {
if (ScriptObject<CardP>* c = dynamic_cast<ScriptObject<CardP>*>(custom->value[i].get())) {
out.push_back(c->getValue());
out.push_back(make_intrusive<Card>(*c->getValue()));
}
}
}
} else if (ScriptObject<CardP>* c = dynamic_cast<ScriptObject<CardP>*>(sv.get())) {
out.push_back(c->getValue());
out.push_back(make_intrusive<Card>(*c->getValue()));
}
} catch (...) {}
} catch (...) {}
// decode images to populate image fields
for (int k = j; k < out.size(); k++) {
CardP& card = out[k];
@@ -394,125 +375,56 @@ bool CardListBase::parseText(String& text, vector<CardP>& out) {
return j < out.size();
}
bool CardListBase::parseData(bool ignore_cards_from_own_card_list) {
bool CardListBase::parseData(bool ignore_cards_from_own_card_list) {
wxBusyCursor wait;
wxDataObjectComposite* composite = drop_target->data_object;
wxDataFormat format = composite->GetReceivedFormat();
wxDataFormat format = drop_target->data_object->GetReceivedFormat();
wxDataObject *data = drop_target->data_object->GetObject(format);
vector<CardP> new_cards;
if (format == CardsDataObject::format) {
if (CardsDataObject* card_data = dynamic_cast<CardsDataObject*>(data)) {
String id = ignore_cards_from_own_card_list ? drop_target->ignored_id : _("");
size_t size = composite->GetDataSize(format);
if (size < 1) {
queue_message(MESSAGE_ERROR, _("DEBUG: CardsDataObject corrupted"));
return false;
}
if (size > 10000000) { // 10Mb
queue_message(MESSAGE_ERROR, _("Too much card data, paste less cards!"));
return false;
}
std::vector<char> buffer(size);
if (composite->GetDataHere(format, buffer.data())) {
CardsDataObject card_data;
card_data.SetData(size, buffer.data());
card_data.getCards(set, id, new_cards);
}
card_data->getCards(set, id, new_cards);
}
else {
wxDataObject *data = composite->GetObject(format);
switch (format.GetType())
else switch (format.GetType())
{
case wxDF_FILENAME:
{
case wxDF_FILENAME:
{
wxFileDataObject* file_data = static_cast<wxFileDataObject*>(data);
wxArrayString filenames = file_data->GetFilenames();
parseFiles(filenames, new_cards);
}
break;
wxFileDataObject* file_data = static_cast<wxFileDataObject*>(data);
wxArrayString filenames = file_data->GetFilenames();
parseFiles(filenames, new_cards);
}
break;
case wxDF_PNG:
{
wxImageDataObject* image_data = static_cast<wxImageDataObject*>(data);
size_t size = image_data->GetDataSize();
if (size < 1) {
queue_message(MESSAGE_ERROR, _("DEBUG: ImageDataObject corrupted"));
return false;
}
if (size > 50000000) { // 50Mb
queue_message(MESSAGE_ERROR, _("Image data too large or corrupted"));
return false;
}
try {
Image image = image_data->GetImage();
if (!image.IsOk() || image.GetWidth() > 20000 || image.GetHeight() > 20000) {
queue_message(MESSAGE_ERROR, _("Image too large or corrupted"));
return false;
}
parseImage(image, new_cards);
} catch (const std::bad_alloc&) {
//queue_message(MESSAGE_ERROR, _("Image couldn't be allocated"));
return false;
} catch (...) {
queue_message(MESSAGE_ERROR, _("Image couldn't be processed"));
return false;
}
}
break;
case wxDF_PNG:
{
wxImageDataObject* image_data = static_cast<wxImageDataObject*>(data);
Image image = image_data->GetImage();
parseImage(image, new_cards);
}
break;
case wxDF_BITMAP:
{
wxBitmapDataObject* bitmap_data = static_cast<wxBitmapDataObject*>(data);
size_t size = bitmap_data->GetDataSize();
if (size < 1) {
queue_message(MESSAGE_ERROR, _("DEBUG: BitmapDataObject corrupted"));
return false;
}
if (size > 50000000) { // 50Mb
queue_message(MESSAGE_ERROR, _("Bitmap data too large or corrupted"));
return false;
}
try {
wxBitmap bitmap = bitmap_data->GetBitmap();
if (!bitmap.IsOk() || bitmap.GetWidth() > 20000 || bitmap.GetHeight() > 20000) {
queue_message(MESSAGE_ERROR, _("Bitmap too large or corrupted"));
return false;
}
Image image = bitmap.ConvertToImage();
parseImage(image, new_cards);
} catch (const std::bad_alloc&) {
//queue_message(MESSAGE_ERROR, _("Bitmap or Image couldn't be allocated"));
return false;
} catch (...) {
queue_message(MESSAGE_ERROR, _("Bitmap or Image couldn't be processed"));
return false;
}
}
break;
case wxDF_BITMAP:
{
wxBitmapDataObject* bitmap_data = static_cast<wxBitmapDataObject*>(data);
wxBitmap bitmap = bitmap_data->GetBitmap();
Image image = bitmap.ConvertToImage();
parseImage(image, new_cards);
}
break;
case wxDF_UNICODETEXT:
case wxDF_TEXT:
case wxDF_HTML:
{
wxTextDataObject* text_data = static_cast<wxTextDataObject*>(data);
size_t size = text_data->GetDataSize();
if (size < 1) {
queue_message(MESSAGE_ERROR, _("DEBUG: TextDataObject corrupted"));
return false;
}
if (size > 30000000) { // 30Mb
queue_message(MESSAGE_ERROR, _("Text too large or corrupted"));
return false;
}
String text = text_data->GetText();
if (!parseUrl(text, new_cards)) parseText(text, new_cards);
}
break;
case wxDF_UNICODETEXT:
case wxDF_TEXT:
case wxDF_HTML:
{
wxTextDataObject* text_data = static_cast<wxTextDataObject*>(data);
String text = text_data->GetText();
if (!parseUrl(text, new_cards)) parseText(text, new_cards);
}
break;
default:
{
queue_message(MESSAGE_ERROR, _ERROR_("unknown data format"));
}
default:
{
queue_message(MESSAGE_ERROR, _ERROR_("unknown data format"));
}
}
@@ -529,8 +441,12 @@ bool CardListBase::canLink() const {
vector<CardP> selected_cards;
getSelection(selected_cards);
if (selected_cards.size() != 1) return false;
unordered_set<String> all_existing_uids;
FOR_EACH(card, set->cards) {
all_existing_uids.insert(card->uid);
}
CardP card = selected_cards[0];
return card->findFreeLink(card->uid, set->card_uids) >= 0;
return card->findFreeLink(card->uid, all_existing_uids) >= 0;
}
bool CardListBase::doLink() {
CardLinkWindow wnd(this, set, getCard());
@@ -560,23 +476,7 @@ bool CardListBase::compareItems(void* a, void* b) const {
// compare sort keys
int cmp = smart_compare( va->getSortKey(), vb->getSortKey() );
if (cmp != 0) return cmp < 0;
// equal values, compare alternate sort keys
if (sort_by_column2 != sort_by_column && sort_by_column2 >= 0) {
FieldP sort_field2 = column_fields[sort_by_column2];
ValueP va2 = reinterpret_cast<Card*>(a)->data[sort_field2];
ValueP vb2 = reinterpret_cast<Card*>(b)->data[sort_field2];
assert(va2 && vb2);
int cmp = smart_compare( va2->getSortKey(), vb2->getSortKey() );
if (cmp != 0) return cmp < 0;
if (sort_by_column3 != sort_by_column && sort_by_column3 != sort_by_column2 && sort_by_column3 >= 0) {
FieldP sort_field3 = column_fields[sort_by_column3];
ValueP va3 = reinterpret_cast<Card*>(a)->data[sort_field3];
ValueP vb3 = reinterpret_cast<Card*>(b)->data[sort_field3];
assert(va3 && vb3);
int cmp = smart_compare( va3->getSortKey(), vb3->getSortKey() );
if (cmp != 0) return cmp < 0;
}
}
// equal values, compare alternate sort key
if (alternate_sort_field) {
ValueP va = reinterpret_cast<Card*>(a)->data[alternate_sort_field];
ValueP vb = reinterpret_cast<Card*>(b)->data[alternate_sort_field];
@@ -616,8 +516,6 @@ void CardListBase::rebuild() {
GameSettings& gs = settings.gameSettingsFor(*set->game);
sort_ascending = gs.sort_cards_ascending;
sort_by_column = -1;
sort_by_column2 = -1;
sort_by_column3 = -1;
long i = 0;
FOR_EACH(f, column_fields) {
if (f->name == gs.sort_cards_by) {
@@ -753,8 +651,7 @@ void CardListBase::onChar(wxKeyEvent& ev) {
}
}
void CardListBase::onBeginDrag(wxListEvent& ev) {
ev.Skip();
void CardListBase::onBeginDrag(wxListEvent&) {
drop_timer.Start(200, wxTIMER_ONE_SHOT);
}
@@ -800,7 +697,6 @@ void CardListBase::onContextMenu(wxContextMenuEvent&) {
add_menu_item_tr(&m, wxID_PASTE, "paste", "paste_card");
m.AppendSeparator();
add_menu_item_tr(&m, ID_CARD_ADD, "card_add", "add card");
add_menu_item_tr(&m, ID_CARD_ADD_DOUBLE, "card_add_double", "add card double");
add_menu_item_tr(&m, ID_CARD_REMOVE, "card_del", "remove card");
add_menu_item_tr(&m, ID_CARD_LINK, settings.darkModePrefix() + "card_link", "link card");
PopupMenu(&m);
@@ -827,7 +723,7 @@ CardListDropTarget::CardListDropTarget(CardListBase* card_list)
CardListDropTarget::~CardListDropTarget() {}
wxDragResult CardListDropTarget::OnData(wxCoord x, wxCoord y, wxDragResult defaultDragResult) {
wxDragResult CardListDropTarget::OnData(wxCoord x, wxCoord y, wxDragResult defaultDragResult) {
if (!GetData()) return wxDragNone;
if (!card_list->parseData(true)) return wxDragError;
return wxDragCopy;
+2 -4
View File
@@ -16,7 +16,7 @@
ItemList::ItemList(Window* parent, int id, long additional_style, bool multi_sel)
: wxListView(parent, id, wxDefaultPosition, wxDefaultSize, additional_style | wxLC_REPORT | wxLC_VIRTUAL | (multi_sel ? 0 : wxLC_SINGLE_SEL))
, selected_item_pos(-1)
, sort_by_column(-1), sort_by_column2(-1), sort_by_column3(-1), sort_ascending(true)
, sort_by_column(-1), sort_ascending(true)
{
// create image list
wxImageList* il = new wxImageList(18,14);
@@ -262,9 +262,7 @@ void ItemList::onColumnClick(wxListEvent& ev) {
} else {
new_sort_by_column = -1; // 3rd click on same column -> don't sort
}
} else {
sort_by_column3 = sort_by_column2;
sort_by_column2 = sort_by_column;
} else {
sort_ascending = true;
}
sortBy(new_sort_by_column, sort_ascending);
-2
View File
@@ -107,8 +107,6 @@ protected:
VoidP selected_item; ///< The currently selected item
long selected_item_pos; ///< Position of the selected item in the sorted_list, or -1 if no card is selected
long sort_by_column; ///< Column to use for sorting, or -1 if not sorted
long sort_by_column2; ///< Previous column used for sorting, or -1 if not sorted
long sort_by_column3; ///< Previous previous column used for sorting, or -1 if not sorted (stable sort aint workin so we doing this I guess)
bool sort_ascending; ///< Sort order
vector<VoidP> sorted_list; ///< Sorted list of items, can be considered a map: pos->item
-2
View File
@@ -109,7 +109,6 @@ bool KeywordList::doCopy() {
if (!canCopy()) return false;
if (!wxTheClipboard->Open()) return false;
bool ok = wxTheClipboard->SetData(new KeywordDataObject(set, getKeyword())); // ignore result
wxTheClipboard->Flush();
wxTheClipboard->Close();
return ok;
}
@@ -126,7 +125,6 @@ bool KeywordList::doPaste() {
if (!wxTheClipboard->Open()) return false;
KeywordDataObject data;
bool ok = wxTheClipboard->GetData(data);
wxTheClipboard->Flush();
wxTheClipboard->Close();
if (!ok) return false;
// add keyword to set
+11 -62
View File
@@ -16,36 +16,18 @@
/// A list of installed and downloadable packages
class PackageUpdateList : public TreeList {
private:
class TreeItem;
public:
typedef intrusive_ptr<TreeItem> TreeItemP;
PackageUpdateList(Window* parent, const InstallablePackages& packages, bool show_only_installable, int id = wxID_ANY);
~PackageUpdateList();
inline InstallablePackageP getSelectedPackage() const {
TreeItem* ti = getSelectedItem();
return ti ? ti->package : InstallablePackageP();
inline InstallablePackageP getSelection() const {
return selection == NOTHING ? InstallablePackageP() : get(selection);
}
inline bool selectionIsGroup() const {
TreeItem* ti = getSelectedItem();
return ti && !ti->package;
inline InstallablePackageP get(size_t item) const {
return static_pointer_cast<TreeItem>(items[item])->package;
}
inline void forEachSelectedPackage(const std::function<void(const InstallablePackageP&)>& fn) const {
forEachPackage(getSelectedItem(), fn);
}
inline bool anySelectedPackage(const std::function<bool(const InstallablePackageP&)>& predicate) const {
return anyPackage(getSelectedItem(), predicate);
}
inline bool allSelectedPackages(const std::function<bool(const InstallablePackageP&)>& predicate) const {
return allPackages(getSelectedItem(), predicate);
}
protected:
// overridden methods from TreeList
void initItems() override;
@@ -56,48 +38,15 @@ protected:
int columnWidth(size_t column) const override;
private:
inline TreeItem* getSelectedItem() const {
return selection >= items.size() ? nullptr : static_pointer_cast<TreeItem>(items[selection]).get();
}
inline void forEachPackage(const TreeItem* item, const std::function<void(const InstallablePackageP&)>& fn) const {
if (!item) return;
if (item->package) {
fn(item->package);
}
for (const auto& child : item->children) {
forEachPackage(child.get(), fn);
}
}
inline bool anyPackage(const TreeItem* item, const std::function<bool(const InstallablePackageP&)>& predicate) const {
if (!item) return false;
if (item->package && predicate(item->package)) {
return true;
}
for (const auto& child : item->children) {
if (anyPackage(child.get(), predicate)) {
return true;
}
}
return false;
}
inline bool allPackages(const TreeItem* item, const std::function<bool(const InstallablePackageP&)>& predicate) const {
if (!item) return false;
if (item->package && !predicate(item->package)) {
return false;
}
for (const auto& child : item->children) {
if (!allPackages(child.get(), predicate)) {
return false;
}
}
return true;
}
/// The list of packages we are displaying
const InstallablePackages& packages;
/// Show only packages with an installer?
bool show_only_installable;
class TreeItem;
public:
typedef intrusive_ptr<TreeItem> TreeItemP;
private:
class TreeItem : public Item {
public:
TreeItem() : position_type(TYPE_OTHER), position_hint(1000000) {}
+38 -80
View File
@@ -86,36 +86,31 @@ void PackageInfoPanel::draw(DC& dc) {
icon_w = icon.GetWidth();
icon_h = icon.GetHeight();
}
dc.DrawBitmap(icon, x+(max_size-icon_w)/2, y+(max_size-icon_h)/2 + 2);
dc.DrawBitmap(icon, x+(max_size-icon_w)/2, y+(max_size-icon_h)/2);
x += max_size;
}
// package info
// package name
x += 7;
dc.SetFont(wxFont(16, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, _("Arial")));
dc.DrawText(d.short_name, x, y);
y += dc.GetCharHeight() + 7;
dc.SetFont(wxFont(12, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, _("Arial")));
if (d.full_name != d.short_name) dc.DrawText(d.full_name, x, y);
dc.DrawText(d.full_name, x, y);
y += dc.GetCharHeight() + 7;
// version
dc.SetFont(*wxNORMAL_FONT);
int dy = dc.GetCharHeight() + 3;
dc.DrawText(_LABEL_("folder name"), x, y);
dc.DrawText(_LABEL_("installed version"), x, y + 1*dy);
dc.DrawText(_LABEL_("installable version"), x, y + 2*dy);
dc.DrawText(_LABEL_("installed version"), x, y);
dc.DrawText(_LABEL_("installable version"), x, y + 1*dy);
//dc.DrawText(_LABEL_("installer size"), x, y + 2*dy);
//dc.DrawText(_LABEL_("installer status"), x, y + 3*dy);
// text size?
int dx = 0, max_dx = 0;
dc.GetTextExtent(_LABEL_("folder name"), &dx, nullptr); max_dx = max(max_dx, dx);
dc.GetTextExtent(_LABEL_("installed version"), &dx, nullptr); max_dx = max(max_dx, dx);
dc.GetTextExtent(_LABEL_("installable version"), &dx, nullptr); max_dx = max(max_dx, dx);
//dc.GetTextExtent(_LABEL_("installer size"), &dx, nullptr); max_dx = max(max_dx, dx);
//dc.GetTextExtent(_LABEL_("installer status"), &dx, nullptr); max_dx = max(max_dx, dx);
x += max_dx + 5;
dc.DrawText(d.name, x, y);
dc.DrawText(package->installed ? package->installed->version.toString() : _LABEL_("no version"), x, y + 1*dy);
dc.DrawText(package->installer ? package->description->version.toString() : _LABEL_("no version"), x, y + 2*dy);
dc.DrawText(package->installed ? package->installed->version.toString() : _LABEL_("no version"), x, y);
dc.DrawText(package->installer ? package->description->version.toString() : _LABEL_("no version"), x, y + 1*dy);
//dc.DrawText(_("?"), x, y + 2*dy);
//dc.DrawText(_("?"), x, y + 3*dy);
}
@@ -199,8 +194,7 @@ void PackagesWindow::init(Window* parent, bool show_only_installable) {
v2->AddStretchSpacer();
v2->Add(keep_button, 0, wxEXPAND | wxBOTTOM, 4);
v2->AddStretchSpacer();
v2->Add(remove_button, 0, wxEXPAND | wxBOTTOM, 0);
v2->SetMinSize(wxSize(170, -1));
v2->Add(remove_button, 0, wxEXPAND | wxBOTTOM, 0);
h->Add(v2);
v->Add(h, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
wxBoxSizer* h2 = new wxBoxSizer(wxHORIZONTAL);
@@ -208,7 +202,7 @@ void PackagesWindow::init(Window* parent, bool show_only_installable) {
h2->AddStretchSpacer();
h2->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | (wxALL & ~wxTOP), 8);
v->Add(h2, 0, wxEXPAND);
v->SetMinSize(820,650);
v->SetMinSize(800,600);
SetSizerAndFit(v);
wxUpdateUIEvent::SetMode(wxUPDATE_UI_PROCESS_SPECIFIED);
@@ -218,27 +212,24 @@ void PackagesWindow::init(Window* parent, bool show_only_installable) {
PackagesWindow::~PackagesWindow() {
}
void PackagesWindow::onPackageSelect(wxCommandEvent& ev) {
package_info->setPackage(package = package_list->getSelectedPackage());
package_info->setPackage(package = package_list->getSelection());
UpdateWindowUI(wxUPDATE_UI_RECURSE);
}
void PackagesWindow::onActionChange(wxCommandEvent& ev) {
PackageAction act = ev.GetId() == ID_INSTALL ? PACKAGE_ACT_INSTALL
: ev.GetId() == ID_UPGRADE ? PACKAGE_ACT_INSTALL
: ev.GetId() == ID_REMOVE ? PACKAGE_ACT_REMOVE
: PACKAGE_ACT_NOTHING;
act = act | where;
// set action
package_list->forEachSelectedPackage(
[&](const InstallablePackageP& p) {
if (p->can(act)) {
set_package_action(installable_packages, p, act);
}
}
);
package_list->Refresh(false);
UpdateWindowUI(wxUPDATE_UI_RECURSE);
if (package) {
PackageAction act = ev.GetId() == ID_INSTALL ? PACKAGE_ACT_INSTALL
: ev.GetId() == ID_UPGRADE ? PACKAGE_ACT_INSTALL
: ev.GetId() == ID_REMOVE ? PACKAGE_ACT_REMOVE
: PACKAGE_ACT_NOTHING;
act = act | where;
// set action
set_package_action(installable_packages, package, act);
package_list->Refresh(false);
UpdateWindowUI(wxUPDATE_UI_RECURSE);
}
}
void PackagesWindow::onOk(wxCommandEvent& ev) {
@@ -377,61 +368,28 @@ void PackagesWindow::onOk(wxCommandEvent& ev) {
//%% NOTE: The above text is for the locale.pl program
}
void PackagesWindow::onUpdateUI(wxUpdateUIEvent& ev) {
bool is_group = package_list->selectionIsGroup();
void PackagesWindow::onUpdateUI(wxUpdateUIEvent& ev) {
wxToggleButton* w = (wxToggleButton*)ev.GetEventObject();
switch (ev.GetId()) {
case ID_KEEP:
w->SetValue(
package_list->allSelectedPackages([&](const InstallablePackageP& p) {
return p->has(PACKAGE_ACT_NOTHING);
})
);
w->Enable(
package_list->anySelectedPackage([&](const InstallablePackageP& p) {
return p->can(PACKAGE_ACT_NOTHING | where);
})
);
w->SetLabel(is_group ? _BUTTON_("keep group") :
package && package->installed ? _BUTTON_("keep package") :
_BUTTON_("don't install package"));
w->SetValue(package && package->has(PACKAGE_ACT_NOTHING));
w->Enable (package && package->can(PACKAGE_ACT_NOTHING | where));
w->SetLabel(package && package->installed ? _BUTTON_("keep package") : _BUTTON_("don't install package"));
break;
case ID_INSTALL:
w->SetValue(
package_list->allSelectedPackages([&](const InstallablePackageP& p) {
return p->has(PACKAGE_ACT_INSTALL | where) ||
(p->has(PACKAGE_INSTALLED) && !p->has(PACKAGE_ACT_REMOVE) && !p->has(PACKAGE_UPDATES));
}) &&
package_list->anySelectedPackage([&](const InstallablePackageP& p) {
return p->has(PACKAGE_ACT_INSTALL | where);
})
);
w->Enable(
package_list->anySelectedPackage([&](const InstallablePackageP& p) {
return p->can(PACKAGE_ACT_INSTALL | where);
})
);
w->SetLabel(is_group ? _BUTTON_("install group") :
!(package && package->installed) ? _BUTTON_("install package") :
(package && package->has(PACKAGE_UPDATES)) ? _BUTTON_("upgrade package") :
_BUTTON_("reinstall package"));
w->SetValue(package && package->has(PACKAGE_ACT_INSTALL | where));
w->Enable (package && package->can(PACKAGE_ACT_INSTALL | where));
w->SetLabel(!(package && package->installed) ? _BUTTON_("install package")
: (package && package->has(PACKAGE_UPDATES)) ? _BUTTON_("upgrade package")
: _BUTTON_("reinstall package"));
break;
case ID_REMOVE:
w->SetValue(
package_list->allSelectedPackages([&](const InstallablePackageP& p) {
return p->has(PACKAGE_ACT_REMOVE | where) ||
(!p->has(PACKAGE_INSTALLED) && !p->has(PACKAGE_ACT_INSTALL));
})
);
w->Enable(
package_list->anySelectedPackage([&](const InstallablePackageP& p) {
return p->can(PACKAGE_ACT_REMOVE | where);
})
);
w->SetLabel(is_group ? _BUTTON_("remove group") :
_BUTTON_("remove package"));
w->SetValue(package && package->has(PACKAGE_ACT_REMOVE | where));
w->Enable (package && package->can(PACKAGE_ACT_REMOVE | where));
//w->SetLabel(package && package->... ? _BUTTON_("remove group") : _BUTTON_("remove package"));
break;
}
// TODO: change labels to _BUTTON_("install group"), _BUTTON_("remove group"), _BUTTON_("upgrade group")
}
void PackagesWindow::onIdle(wxIdleEvent& ev) {
@@ -451,7 +409,7 @@ bool PackagesWindow::checkInstallerList(bool refresh) {
// refresh
if (refresh) {
package_list->rebuild();
package_info->setPackage(package = package_list->getSelectedPackage());
package_info->setPackage(package = package_list->getSelection());
UpdateWindowUI(wxUPDATE_UI_RECURSE);
}
return true;
+1 -1
View File
@@ -37,7 +37,7 @@ void PrintJob::measure_cards() {
if (already_measured_cards.find(card) != already_measured_cards.end()) continue;
already_measured_cards.emplace(card);
card_layouts.emplace_back(measure_card(card));
CardP other_face = card->getLinkedOtherFaceCard(*set); // we assume that if you want to print one side, you also want to print the other, so we look for it in the entire set instead of just the given cards
CardP other_face = card->getLinkedOtherFaceCard(cards);
if (other_face && already_measured_cards.find(other_face) == already_measured_cards.end()) {
already_measured_cards.emplace(other_face);
card_layouts.emplace_back(measure_card(other_face));
+4 -18
View File
@@ -127,14 +127,13 @@ CardsPanel::CardsPanel(Window* parent, int id)
add_menu_item_tr(menuCard, ID_CARD_NEXT, nullptr, "next card");
add_menu_item_tr(menuCard, ID_CARD_SEARCH, nullptr, "search cards");
menuCard->AppendSeparator();
add_menu_item_tr(menuCard, ID_CARD_ADD, "card_add", "add_card");
add_menu_item_tr(menuCard, ID_CARD_ADD_DOUBLE, "card_add_double", "add_card_double");
insertManyCardsMenu = add_menu_item_tr(menuCard, ID_CARD_ADD_MULT, "card_add_multiple", "add cards");
// NOTE: space after "Del" prevents wx from making del an accellerator
// otherwise we delete a card when delete is pressed inside the editor
// Adding a space never hurts, please keep it just to be safe.
add_menu_item(menuCard, ID_CARD_ADD_CSV, "card_add_multiple", _MENU_("add card csv") + _(" "), _HELP_("add card csv"));
add_menu_item(menuCard, ID_CARD_ADD_JSON, "card_add_multiple", _MENU_("add card json") + _(" "), _HELP_("add card json"));
add_menu_item_tr(menuCard, ID_CARD_ADD, "card_add", "add_card");
add_menu_item(menuCard, ID_CARD_REMOVE, "card_del", _MENU_("remove card")+_(" "), _HELP_("remove card"));
add_menu_item(menuCard, ID_CARD_LINK, settings.darkModePrefix() + "card_link", _MENU_("link card") + _(" "), _HELP_("link card"));
add_menu_item(menuCard, ID_CARD_AND_LINK_COPY, "card_copy", _MENU_("copy card and links") + _(" "), _HELP_("copy card and links"));
@@ -256,7 +255,7 @@ void CardsPanel::onChangeSet() {
insertManyCardsMenu->SetSubMenu(makeAddCardsSubmenu(false));
// re-add the menu
menuCard->Remove(ID_CARD_ADD_MULT);
((wxMenu*)menuCard)->Insert(6,insertManyCardsMenu); // HACK: the position is hardcoded
((wxMenu*)menuCard)->Insert(4,insertManyCardsMenu); // HACK: the position is hardcoded
// also for the toolbar dropdown menu
if (toolAddCard) {
// Originally this was using the menu directly, but there are compatibility issues apparently.
@@ -271,7 +270,6 @@ wxMenu* CardsPanel::makeAddCardsSubmenu(bool add_single_card_option) {
if (add_single_card_option) {
cards_scripts_menu = new wxMenu();
add_menu_item_tr(cards_scripts_menu, ID_CARD_ADD, "card_add", "add_card");
add_menu_item_tr(cards_scripts_menu, ID_CARD_ADD_DOUBLE, "card_add_double", "add_card_double");
cards_scripts_menu->AppendSeparator();
}
// create menu for add_cards_scripts
@@ -437,17 +435,6 @@ void CardsPanel::onCommand(int id) {
case ID_CARD_ADD:
set->actions.addAction(make_unique<AddCardAction>(*set));
break;
case ID_CARD_ADD_DOUBLE: {
vector<CardP> cards;
cards.push_back(make_intrusive<Card>(*set->game));
cards.push_back(make_intrusive<Card>(*set->game));
cards[0]->linked_card_1 = cards[1]->uid;
cards[1]->linked_card_1 = cards[0]->uid;
cards[0]->linked_relation_1 = "Back Face";
cards[1]->linked_relation_1 = "Front Face";
set->actions.addAction(make_unique<AddCardAction>(ADD, *set, cards));
break;
}
case ID_CARD_ADD_CSV:
card_list->doAddCSV();
break;
@@ -579,7 +566,7 @@ bool CardsPanel::canPaste() const {
else return false;
}
void CardsPanel::doPaste() {
if (card_list->doPaste()) return;
if (card_list->doPaste()) return;
int id = focused_control(this);
if (id == ID_EDITOR) editor->doPaste();
@@ -667,9 +654,8 @@ CardP CardsPanel::selectedCard() const {
return card_list->getCard();
}
void CardsPanel::selectCard(const CardP& card) {
if (!set) return; // we want onChangeSet first
if (!set) return; // we want onChangeSet first
card_list->SetFocus();
card_list->setCard(card);
editor->setCard(card);
+3 -7
View File
@@ -14,7 +14,6 @@
#include <util/window_id.hpp>
#include <data/stylesheet.hpp>
#include <data/card.hpp>
#include <script/functions/json.hpp>
#include <wx/splitter.h>
#include <wx/dcbuffer.h>
#include <wx/clipbrd.h>
@@ -108,7 +107,6 @@ public:
} else {
ok = wxTheClipboard->SetData(new wxTextDataObject(msg.text));
}
wxTheClipboard->Flush();
wxTheClipboard->Close();
return ok;
}
@@ -625,7 +623,7 @@ void ConsolePanel::exec(String const& command) {
// type of result
ScriptType type = result->type();
if (type == SCRIPT_IMAGE) {
GeneratedImage::Options options(0,0, card->stylesheet ? card->stylesheet.get() : set->stylesheet.get(), set.get());
GeneratedImage::Options options(0,0, set->stylesheet.get(), set.get());
wxImage image = result->toImage()->generate(options);
message->bitmap = wxBitmap(image);
} else if (type == SCRIPT_COLOR) {
@@ -635,10 +633,8 @@ void ConsolePanel::exec(String const& command) {
fill_image(image,color);
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);
} else {
message->text = result->toCode();
}
messages->add_message(message);
} catch (ScriptError const& e) {
+1 -2
View File
@@ -308,8 +308,7 @@ void SetWindow::onChangeSet() {
updateTitle();
// make sure there is always at least one card
// some things need this
if (set->cards.empty()) set->cards.push_back(make_intrusive<Card>(*set->game));
set->buildUIDMap();
if (set->cards.empty()) set->cards.push_back(make_intrusive<Card>(*set->game));
// all panels view the same set
FOR_EACH(p, panels) {
p->setSet(set);
+1 -1
View File
@@ -98,7 +98,7 @@ void SymbolWindow::init(Window* parent, SymbolP symbol) {
add_menu_item_tr(menuTool, ID_MODE_POINTS, "mode_curve", "points", wxITEM_CHECK);
add_menu_item_tr(menuTool, ID_MODE_SHAPES, settings.darkModePrefix() + "circle", "basic_shapes", wxITEM_CHECK);
add_menu_item_tr(menuTool, ID_MODE_SYMMETRY, "mode_symmetry", "symmetry", wxITEM_CHECK);
//add_menu_item_tr(menuTool, ID_MODE_PAINT, settings.darkModePrefix() + "mode_paint", "paint", wxITEM_CHECK);
add_menu_item_tr(menuTool, ID_MODE_PAINT, settings.darkModePrefix() + "mode_paint", "paint", wxITEM_CHECK);
menuBar->Append(menuTool, _MENU_("tool"));
SetMenuBar(menuBar);
+2 -4
View File
@@ -92,8 +92,7 @@ bool ImageValueEditor::doCopy() {
if (!image_load_file(image, *image_file)) return false;
// set data
if (!wxTheClipboard->Open()) return false;
bool ok = wxTheClipboard->SetData(new wxBitmapDataObject(image));
wxTheClipboard->Flush();
bool ok = wxTheClipboard->SetData(new wxBitmapDataObject(image));
wxTheClipboard->Close();
return ok;
}
@@ -102,8 +101,7 @@ bool ImageValueEditor::doPaste() {
// get bitmap
if (!wxTheClipboard->Open()) return false;
wxBitmapDataObject data;
bool ok = wxTheClipboard->GetData(data);
wxTheClipboard->Flush();
bool ok = wxTheClipboard->GetData(data);
wxTheClipboard->Close();
if (!ok) return false;
// slice
+2 -4
View File
@@ -782,8 +782,7 @@ bool TextValueEditor::doPaste() {
// get data
if (!wxTheClipboard->Open()) return false;
wxTextDataObject data;
bool ok = wxTheClipboard->GetData(data);
wxTheClipboard->Flush();
bool ok = wxTheClipboard->GetData(data);
wxTheClipboard->Close();
if (!ok) return false;
// paste
@@ -801,8 +800,7 @@ bool TextValueEditor::doCopy() {
if (str.empty()) return false; // no data to copy
// set data
if (!wxTheClipboard->Open()) return false;
bool ok = wxTheClipboard->SetData(new wxTextDataObject(str));
wxTheClipboard->Flush();
bool ok = wxTheClipboard->SetData(new wxTextDataObject(str));
wxTheClipboard->Close();
return ok;
}
+4 -39
View File
@@ -9,7 +9,6 @@
#include <util/prec.hpp>
#include <gui/web_request_window.hpp>
#include <util/window_id.hpp>
#include <wx/mstream.h>
// ----------------------------------------------------------------------------- : WebRequestWindow
@@ -77,50 +76,16 @@ void WebRequestWindow::onUpdate(wxWebRequestEvent& evt) {
}
void WebRequestWindow::onComplete(wxWebRequestEvent& evt) {
wxWebResponse response = evt.GetResponse();
if (!response.IsOk()) {
onFail(_ERROR_("web request corrupted"));
return;
}
wxInputStream* stream = response.GetStream();
if (!stream || !stream->IsOk()) {
onFail(_ERROR_("web request corrupted"));
return;
}
content_type = response.GetContentType();
if (content_type.StartsWith("image/")) {
image_out = Image(*stream);
if (!image_out.IsOk()) {
onFail(_ERROR_("web request corrupted"));
return;
}
}
else if (content_type.StartsWith("text/") || content_type.Contains("json")) {
wxMemoryOutputStream mem;
char buffer[8192];
while (true) {
stream->Read(buffer, sizeof(buffer));
size_t read = stream->LastRead();
if (read > 0) mem.Write(buffer, read);
if (stream->Eof()) break;
if (stream->GetLastError() != wxSTREAM_NO_ERROR) {
onFail(_ERROR_("web request corrupted"));
return;
}
}
text_out.resize(mem.GetSize());
mem.CopyTo(text_out.data(), mem.GetSize());
out = evt.GetResponse();
if (out.IsOk()) {
EndModal(wxID_OK);
}
else {
onFail(_ERROR_("web request unsupported format"));
return;
onFail(_ERROR_("web request corrupted"));
}
EndModal(wxID_OK);
}
void WebRequestWindow::onFail(const String& message) {
content_type.Clear();
info->SetLabel(_ERROR_("web request failed"));
address->SetLabel(message);
}
+1 -3
View File
@@ -19,9 +19,7 @@ class WebRequestWindow : public wxDialog {
public:
WebRequestWindow(const String& url, bool sizer=true);
String content_type;
std::string text_out;
Image image_out;
wxWebResponse out;
protected:
DECLARE_EVENT_TABLE();
+9 -25
View File
@@ -105,40 +105,24 @@ RealRect intersect(const RealRect& a, const RealRect& b) {
RealPoint tl = piecewise_max(a.topLeft(), b.topLeft());
RealPoint br = piecewise_min(a.bottomRight(), b.bottomRight());
return RealRect(tl, RealSize(br - tl));
}
}
void TextViewer::drawSelection(RotatedDC& dc, const TextStyle& style, size_t sel_start, size_t sel_end) {
if (sel_start == sel_end) return;
if (sel_end < sel_start) swap(sel_start, sel_end);
#ifdef __WXMSW__
dc.SetBrush(*wxWHITE_BRUSH);
dc.SetPen(*wxWHITE_PEN);
dc.SetLogicalFunction(wxXOR);
#endif
if (sel_end < sel_start) swap(sel_start, sel_end);
dc.SetBrush(*wxBLACK_BRUSH);
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetLogicalFunction(wxINVERT);
RealRect prev_rect(0,0,0,0);
FOR_EACH(l, lines) {
RealRect rect = l.selectionRectangle(dc, sel_start, sel_end);
if (rect.height > 0) {
#ifdef __WXMSW__
dc.DrawRectangle(rect);
#else
dc.DrawInvertRectangle(rect);
#endif
}
if (rect.height > 0) dc.DrawRectangle(rect);
// compensate for overlap between lines
RealRect overlap = intersect(rect, prev_rect);
if (overlap.height > 0 && overlap.width > 0) {
#ifdef __WXMSW__
dc.DrawRectangle(overlap);
#else
dc.DrawInvertRectangle(overlap);
#endif
}
if (overlap.height > 0 && overlap.width > 0) dc.DrawRectangle(overlap);
prev_rect = rect;
}
#ifdef __WXMSW__
dc.SetLogicalFunction(wxCOPY);
#endif
}
dc.SetLogicalFunction(wxCOPY);
}
RealRect TextViewer::Line::selectionRectangle(const Rotation& rot, size_t sel_start, size_t sel_end) {
+3 -4
View File
@@ -116,15 +116,14 @@ Bitmap ImageValueViewer::imagePlaceholder(const Rotation& rot, UInt w, UInt h, c
}
// Draw text
if (editing) {
// only when in editor mode
String label = _LABEL_("load image");
// only when in editor mode
for (UInt size = 12 ; size > 2 ; --size) {
dc.SetFont(wxFont(size, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
RealSize rs = dc.GetTextExtent(label);
RealSize rs = dc.GetTextExtent(_LABEL_("load image"));
if (rs.width <= w - 10 && rs.height < h - 10) {
// text fits
RealPoint pos = align_in_rect(ALIGN_MIDDLE_CENTER, rs, rect);
dc.DrawText(label, pos, Color(255,255,255), 2, Color(0,0,0), 3); // stroked
dc.DrawText(_LABEL_("load image"), pos, Color(255,255,255), 2, Color(0,0,0), 3); // stroked
break;
}
}
-18
View File
@@ -90,22 +90,6 @@ SCRIPT_FUNCTION(error) {
return script_nil;
}
SCRIPT_FUNCTION(version_is_older) {
SCRIPT_PARAM_C(String, input);
SCRIPT_PARAM(String, than);
Version input_version = Version::fromString(input);
Version than_version = Version::fromString(than);
SCRIPT_RETURN(input_version < than_version);
}
SCRIPT_FUNCTION(exists_as_package) {
SCRIPT_PARAM_C(String, input);
Version version_out;
bool result = package_manager.installedVersion(input, version_out);
if (!result) return script_nil;
SCRIPT_RETURN(version_out.toString());
}
SCRIPT_FUNCTION(exists_in_package) {
SCRIPT_PARAM_C(String, input);
bool result = package_manager.existsInPackage(input);
@@ -1034,8 +1018,6 @@ void init_script_basic_functions(Context& ctx) {
ctx.setVariable(_("trace"), script_trace);
ctx.setVariable(_("warning"), script_warning);
ctx.setVariable(_("error"), script_error);
ctx.setVariable(_("version_is_older"), script_version_is_older);
ctx.setVariable(_("exists_as_package"), script_exists_as_package);
ctx.setVariable(_("exists_in_package"), script_exists_in_package);
// conversion
ctx.setVariable(_("to_string"), script_to_string);
+7 -21
View File
@@ -19,20 +19,17 @@
#include <data/game.hpp>
#include <data/stylesheet.hpp>
#include <data/card.hpp>
#include <util/uid.hpp>
#include <util/error.hpp>
// ----------------------------------------------------------------------------- : new_card
SCRIPT_FUNCTION(new_card) {
SCRIPT_PARAM(GameP, game);
ScriptValueP set_ = ctx.getVariableOpt(BOOST_PP_CAT(L, "set")); // this is just SCRIPT_OPTIONAL_PARAM_(Set*, set) but the macro fails
Set* set = set_ && set_ != script_nil ? from_script<Set*>(set_, BOOST_PP_CAT(L, "set")) : nullptr;
SCRIPT_OPTIONAL_PARAM_(bool, ignore_field_not_found);
SCRIPT_OPTIONAL_PARAM_(CardP, copy_from);
// create a new card object
CardP new_card = make_intrusive<Card>(*game);
// iterate on the given key/value pairs
SCRIPT_PARAM(ScriptValueP, input);
// create a new card object, or a copy
CardP new_card = copy_from ? make_intrusive<Card>(set, copy_from) : make_intrusive<Card>(*game);
// check for a stylesheet first, since other things depend on it
ScriptValueP it = input->makeIterator();
ScriptValueP key;
@@ -41,7 +38,7 @@ SCRIPT_FUNCTION(new_card) {
if (key == script_nil || value == script_nil) continue;
String key_name = key->toString();
if (set_stylesheet_container(*game, new_card, value, key_name, ignore_field_not_found)) break;
}
}
// set the rest of the key/value pairs
it = input->makeIterator();
while (ScriptValueP value = it->next(&key)) {
@@ -100,7 +97,7 @@ SCRIPT_FUNCTION(new_card) {
else {
set_container(container, value, key_name);
}
}
}
// if the game has a construction script, set the card context variable to be this card, run script
if (game->import_script) {
ScriptValueP ctx_card = ctx.getVariableOpt(SCRIPT_VAR_card);
@@ -136,7 +133,7 @@ SCRIPT_FUNCTION(new_card) {
}
// restore old context card
if (ctx_card) ctx.setVariable(SCRIPT_VAR_card, ctx_card);
}
}
SCRIPT_RETURN(new_card);
}
@@ -169,22 +166,11 @@ SCRIPT_FUNCTION(add_card_to_set) {
}
}
SCRIPT_RETURN(false);
}
SCRIPT_FUNCTION(new_uid) {
SCRIPT_PARAM_C(Set*, set);
String uid = generate_uid();
for (int i = 0; i < 100; i++) {
if (set->card_uids.find(uid) == set->card_uids.end()) break;
uid = generate_uid();
}
SCRIPT_RETURN(uid);
}
// ----------------------------------------------------------------------------- : Init
void init_script_construction_functions(Context& ctx) {
ctx.setVariable(_("new_card"), script_new_card);
ctx.setVariable(_("new_uid"), script_new_uid);
ctx.setVariable(_("add_card_to_set"), script_add_card_to_set);
}
+4 -16
View File
@@ -62,9 +62,7 @@ inline static void set_container(Value* container, ScriptValueP& value, String k
cvalue->value = value->toString();
}
else if (PackageChoiceValue* pvalue = dynamic_cast<PackageChoiceValue*>(container)) {
String package_name = value->toString();
while (package_name.starts_with(_("/"))) package_name = package_name.substr(1);
pvalue->package_name = package_name;
pvalue->package_name = value->toString();
}
else if (ColorValue* cvalue = dynamic_cast<ColorValue*>(container)) {
cvalue->value = value->toColor();
@@ -96,10 +94,7 @@ inline static bool set_stylesheet_container(const Game& game, CardP& card, Scrip
if (key_name == _("style") || key_name == _("stylesheet") || key_name == _("template")) {
if (!trim(value->toString()).empty()) {
card->stylesheet = StyleSheet::byGameAndName(game, value->toString());
if (card->stylesheet) {
card->styling_data.init(card->stylesheet->styling_fields);
card->extraDataFor(*card->stylesheet).init(card->stylesheet->extra_card_fields);
}
if (card->stylesheet) card->styling_data.init(card->stylesheet->styling_fields);
}
return true;
}
@@ -109,14 +104,7 @@ inline static bool set_stylesheet_container(const Game& game, CardP& card, Scrip
inline static bool set_builtin_container(const Game& game, CardP& card, ScriptValueP& value, String key_name, bool ignore_field_not_found) {
// check if the given value is for a built-in field, if found set it and return true
key_name = unified_form(key_name);
if (key_name == _("style") || key_name == _("stylesheet") || key_name == _("template")) {
return true; // we already took care of this
}
else if (key_name == _("style_version") || key_name == _("stylesheet_version") || key_name == _("template_version")) {
card->stylesheet_version = Version::fromString(value->toString());
return true;
}
else if (key_name == _("card_notes") || key_name == _("notes") || key_name == _("note")) {
if (key_name == _("card_notes") || key_name == _("notes") || key_name == _("note")) {
card->notes = value->toString();
return true;
}
@@ -249,7 +237,7 @@ inline static bool cards_from_table(SetP& set, vector<String>& headers, std::vec
// is this a new card?
if (contains(set->cards, card) || contains(cards_out, card)) {
// make copy
card = make_intrusive<Card>(set.get(), card);
card = make_intrusive<Card>(*card);
}
cards_out.push_back(card);
}
-8
View File
@@ -187,13 +187,6 @@ SCRIPT_FUNCTION_DEPENDENCIES(combined_editor) {
}
}
return dependency_dummy;
}
// ----------------------------------------------------------------------------- : Values
SCRIPT_FUNCTION(is_default) {
SCRIPT_PARAM_C(ValueP,input);
SCRIPT_RETURN(input->isDefault());
}
// ----------------------------------------------------------------------------- : Choice values
@@ -396,7 +389,6 @@ SCRIPT_FUNCTION(count_chosen) {
void init_script_editor_functions(Context& ctx) {
ctx.setVariable(_("forward_editor"), script_combined_editor); // compatability
ctx.setVariable(_("combined_editor"), script_combined_editor);
ctx.setVariable(_("is_default"), script_is_default);
ctx.setVariable(_("primary_choice"), script_primary_choice);
ctx.setVariable(_("chosen"), script_chosen);
ctx.setVariable(_("count_chosen"), script_count_chosen);
+14 -59
View File
@@ -7,7 +7,6 @@
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <script/functions/english_exceptions.cpp>
#include <script/functions/functions.hpp>
#include <script/functions/util.hpp>
#include <util/tagged_string.hpp>
@@ -153,22 +152,8 @@ SCRIPT_FUNCTION(english_number_ordinal) {
// ----------------------------------------------------------------------------- : Singular/plural
String english_singular(const String& str) {
if (str.empty()) return String();
String lower = str.Lower();
if (english_singular_exceptions.find(lower) != english_singular_exceptions.end()) {
if (isupper(str[0])) {
if (isupper(str[str.size()-1])) {
return english_singular_exceptions[lower].Upper();
} else {
return capitalize(english_singular_exceptions[lower]);
}
} else {
return english_singular_exceptions[lower];
}
}
String english_singular(const String& str) {
if (str.Lower() == _("plains")) return str;
if (str.size() > 3 && is_substr(str, str.size()-3, _("ies"))) {
return str.substr(0, str.size() - 3) + _("y");
} else if (str.size() > 3 && is_substr(str, str.size()-3, _("oes"))) {
@@ -189,22 +174,8 @@ String english_singular(const String& str) {
return str;
}
}
String english_plural(const String& str) {
if (str.empty()) return String();
String lower = str.Lower();
if (english_plural_exceptions.find(lower) != english_plural_exceptions.end()) {
if (isupper(str[0])) {
if (isupper(str[str.size()-1])) {
return english_plural_exceptions[lower].Upper();
} else {
return capitalize(english_plural_exceptions[lower]);
}
} else {
return english_plural_exceptions[lower];
}
}
String english_plural(const String& str) {
if (str.Lower() == _("plains")) return str;
if (str.size() > 2) {
Char a = str.GetChar(str.size() - 2);
Char b = str.GetChar(str.size() - 1);
@@ -269,9 +240,7 @@ String process_english_hints(const String& str) {
String ret; ret.reserve(str.size());
// have we seen a <hint-1/2>?
// 1 for singular, 2 for plural
int singplur = 0;
int sing_found = 0;
int plur_found = 0;
int singplur = 0;
for (size_t i = 0 ; i < str.size() ; ) {
Char c = str.GetChar(i);
if (is_substr(str, i, _("<hint-"))) {
@@ -290,7 +259,7 @@ String process_english_hints(const String& str) {
// a -> an, where the a originates from english_number_a(1)
size_t after_end = skip_tag(str,after+1);
if (after_end == String::npos) {
throw ScriptError(_("Incomplete </param> tag"));
throw Error(_("Incomplete </param> tag"));
}
if (after_end != String::npos && after_end + 1 < str.size()
&& isSpace(str.GetChar(after_end)) && is_vowel(str.GetChar(after_end+1))) {
@@ -315,31 +284,23 @@ String process_english_hints(const String& str) {
}
ret.append(str,i,min(after,str.size())-i);
i = after;
} else if (is_substr(str, i, _("<singular>"))) {
sing_found++;
} else if (is_substr(str, i, _("<singular>"))) {
// singular -> keep, plural -> drop
size_t start = skip_tag(str, i);
size_t end = match_close_tag(str, i);
if (end == String::npos) {
throw ScriptError(_("<singular> tag found without matching closing tag."));
}
else if (singplur == 1) {
size_t end = match_close_tag(str, start);
if (singplur == 1 && end != String::npos) {
ret += str.substr(start, end - start);
singplur = 0;
}
singplur = 0;
i = skip_tag(str, end);
} else if (is_substr(str, i, _("<plural>"))) {
plur_found++;
} else if (is_substr(str, i, _("<plural>"))) {
// singular -> drop, plural -> keep
size_t start = skip_tag(str, i);
size_t end = match_close_tag(str, i);
if (end == String::npos) {
throw ScriptError(_("<plural> tag found without matching closing tag."));
}
else if (singplur == 2) {
size_t end = match_close_tag(str, start);
if (singplur == 2 && end != String::npos) {
ret += str.substr(start, end - start);
singplur = 0;
}
singplur = 0;
i = skip_tag(str, end);
} else if (c == _('(') && singplur) {
// singular -> drop (...), plural -> keep it
@@ -362,12 +323,6 @@ String process_english_hints(const String& str) {
ret += c;
++i;
}
}
if (sing_found > plur_found) {
throw ScriptError(_("<singular> tag found without matching <plural> tag."));
}
else if (sing_found < plur_found) {
throw ScriptError(_("<plural> tag found without matching <singular> tag."));
}
return ret;
}
-787
View File
@@ -1,787 +0,0 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make card games |
//| Copyright: (C) Twan van Laarhoven and the other MSE developers |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
// ----------------------------------------------------------------------------- : Maps
inline std::unordered_map<String, String> english_plural_exceptions {
{ "plains", "plains" }
, { "advisor", "advisors" }
, { "aetherborn", "aetherborn" }
, { "alien", "aliens" }
, { "ally", "allies" }
, { "angel", "angels" }
, { "antelope", "antelopes" }
, { "ape", "apes" }
, { "archer", "archers" }
, { "archon", "archons" }
, { "armadillo", "armadillos" }
, { "army", "armies" }
, { "artificer", "artificers" }
, { "assassin", "assassins" }
, { "assembly-worker", "assembly-workers" }
, { "astartes", "astartes" }
, { "atog", "atogs" }
, { "aurochs", "aurochs" }
, { "avatar", "avatars" }
, { "azra", "azra" }
, { "badger", "badgers" }
, { "balloon", "balloons" }
, { "barbarian", "barbarians" }
, { "bard", "bards" }
, { "basilisk", "basilisks" }
, { "bat", "bats" }
, { "bear", "bears" }
, { "beast", "beasts" }
, { "beaver", "beavers" }
, { "beeble", "beebles" }
, { "beholder", "beholders" }
, { "berserker", "berserkers" }
, { "bird", "birds" }
, { "bison", "bison" }
, { "blinkmoth", "blinkmoths" }
, { "boar", "boars" }
, { "bringer", "bringers" }
, { "brushwagg", "brushwaggs" }
, { "c'tan", "c'tan" }
, { "camarid", "camarids" }
, { "camel", "camels" }
, { "capybara", "capybaras" }
, { "caribou", "caribou" }
, { "carrier", "carriers" }
, { "cat", "cats" }
, { "centaur", "centaurs" }
, { "child", "children" }
, { "chimera", "chimeras" }
, { "citizen", "citizens" }
, { "cleric", "clerics" }
, { "clown", "clowns" }
, { "cockatrice", "cockatrices" }
, { "construct", "constructs" }
, { "coward", "cowards" }
, { "coyote", "coyotes" }
, { "crab", "crabs" }
, { "crocodile", "crocodiles" }
, { "custodes", "custodes" }
, { "cyberman", "cybermen" }
, { "cyclops", "cyclopes" }
, { "dalek", "daleks" }
, { "dauthi", "dauthi" }
, { "demigod", "demigods" }
, { "demon", "demons" }
, { "deserter", "deserters" }
, { "detective", "detectives" }
, { "devil", "devils" }
, { "dinosaur", "dinosaurs" }
, { "djinn", "djinn" }
, { "doctor", "doctors" }
, { "dog", "dogs" }
, { "dragon", "dragons" }
, { "drake", "drakes" }
, { "dreadnought", "dreadnoughts" }
, { "drix", "drix" }
, { "drone", "drones" }
, { "druid", "druids" }
, { "dryad", "dryads" }
, { "dwarf", "dwarves" }
, { "echidna", "echdnas" }
, { "efreet", "efreets" }
, { "egg", "eggs" }
, { "elder", "elders" }
, { "eldrazi", "eldrazi" }
, { "elemental", "elementals" }
, { "elephant", "elephants" }
, { "elf", "elves" }
, { "elk", "elk" }
, { "employee", "employees" }
, { "eternal", "eternals" }
, { "eye", "eyes" }
, { "faerie", "faeries" }
, { "ferret", "ferrets" }
, { "fish", "fish" }
, { "flagbearer", "flagbearers" }
, { "fox", "foxes" }
, { "fractal", "fractals" }
, { "frog", "frogs" }
, { "fungus", "fungi" }
, { "gamer", "gamers" }
, { "gamma", "gamma mutates" }
, { "gargoyle", "gargoyles" }
, { "germ", "germs" }
, { "giant", "giants" }
, { "giraffe", "giraffes" }
, { "gith", "gith" }
, { "glimmer", "glimmers" }
, { "gnoll", "gnolls" }
, { "gnome", "gnomes" }
, { "goat", "goats" }
, { "goblin", "goblins" }
, { "god", "gods" }
, { "golem", "golems" }
, { "gorgon", "gorgons" }
, { "graveborn", "graveborn" }
, { "gremlin", "gremlins" }
, { "griffin", "griffins" }
, { "guest", "guests" }
, { "hag", "hags" }
, { "halfling", "halflings" }
, { "hamster", "hamsters" }
, { "harpy", "harpies" }
, { "hedgehog", "hedgehogs" }
, { "hellion", "hellions" }
, { "hero", "heroes" }
, { "hippo", "hippos" }
, { "hippogriff", "hippogriffs" }
, { "homarid", "homarids" }
, { "homunculus", "homunculi" }
, { "horror", "horrors" }
, { "horse", "horses" }
, { "human", "humans" }
, { "hydra", "hydras" }
, { "hyena", "hyenas" }
, { "illusion", "illusions" }
, { "imp", "imps" }
, { "incarnation", "incarnations" }
, { "inkling", "inklings" }
, { "inquisitor", "inquisitors" }
, { "insect", "insects" }
, { "jackal", "jackals" }
, { "jellyfish", "jellyfish" }
, { "juggernaut", "juggernauts" }
, { "kangaroo", "kangaroos" }
, { "kavu", "kavu" }
, { "kirin", "kirin" }
, { "kithkin", "kithkin" }
, { "knight", "knights" }
, { "kobold", "kobolds" }
, { "kor", "kor" }
, { "kraken", "krakens" }
, { "lamia", "lamia" }
, { "lammasu", "lammasu" }
, { "leech", "leeches" }
, { "lemur", "lemurs" }
, { "leviathan", "leviathans" }
, { "lhurgoyf", "lhurgoyfs" }
, { "licid", "licids" }
, { "lizard", "lizards" }
, { "llama", "llamas" }
, { "lobster", "lobsters" }
, { "manticore", "manticores" }
, { "masticore", "masticores" }
, { "mercenary", "mercenaries" }
, { "merfolk", "merfolk" }
, { "metathran", "metathran" }
, { "minion", "minions" }
, { "minotaur", "minotaurs" }
, { "mite", "mites" }
, { "mole", "moles" }
, { "monger", "mongers" }
, { "mongoose", "mongooses" }
, { "monk", "monks" }
, { "monkey", "monkeys" }
, { "moogle", "moogles" }
, { "moonfolk", "moonfolk" }
, { "mount", "mounts" }
, { "mouse", "mice" }
, { "mutant", "mutants" }
, { "myr", "myr" }
, { "mystic", "mystics" }
, { "nautilus", "nautiluses" }
, { "necron", "necrons" }
, { "nephilim", "nephilim" }
, { "nightmare", "nightmares" }
, { "nightstalker", "nightstalkers" }
, { "ninja", "ninja" }
, { "noble", "nobles" }
, { "noggle", "noggles" }
, { "nomad", "nomads" }
, { "nymph", "nymphs" }
, { "octopus", "octopuses" }
, { "ogre", "ogres" }
, { "ooze", "oozes" }
, { "orb", "orbs" }
, { "orc", "orcs" }
, { "orgg", "orggs" }
, { "otter", "otters" }
, { "ouphe", "ouphes" }
, { "ox", "oxen" }
, { "oyster", "oysters" }
, { "pangolin", "pangolins" }
, { "peasant", "peasants" }
, { "pegasus", "pegasi" }
, { "pentavite", "pentavites" }
, { "performer", "performers" }
, { "pest", "pests" }
, { "phelddagrif", "phelddagrifs" }
, { "phoenix", "phoenixes" }
, { "phyrexian", "phyrexians" }
, { "pilot", "pilots" }
, { "pincher", "pinchers" }
, { "pirate", "pirates" }
, { "plant", "plants" }
, { "platypus", "platypuses" }
, { "porcupine", "porcupines" }
, { "possum", "possums" }
, { "praetor", "praetors" }
, { "primarch", "primarchs" }
, { "prism", "prisms" }
, { "processor", "processors" }
, { "qu", "qu" }
, { "rabbit", "rabbits" }
, { "raccoon", "raccoons" }
, { "ranger", "rangers" }
, { "rat", "rats" }
, { "rebel", "rebels" }
, { "reflection", "reflections" }
, { "rhino", "rhinos" }
, { "rigger", "riggers" }
, { "robot", "robots" }
, { "rogue", "rogues" }
, { "sable", "sables" }
, { "salamander", "salamanders" }
, { "samurai", "samurai" }
, { "sand", "sands" }
, { "saproling", "saprolings" }
, { "satyr", "satyrs" }
, { "scarecrow", "scarecrows" }
, { "scientist", "scientists" }
, { "scion", "scions" }
, { "scorpion", "scorpions" }
, { "scout", "scouts" }
, { "sculpture", "sculptures" }
, { "seal", "seals" }
, { "serf", "serfs" }
, { "serpent", "serpents" }
, { "servo", "servos" }
, { "shade", "shades" }
, { "shaman", "shamans" }
, { "shapeshifter", "shapeshifters" }
, { "shark", "sharks" }
, { "sheep", "sheep" }
, { "siren", "sirens" }
, { "skeleton", "skeletons" }
, { "skrull", "skrulls" }
, { "skunk", "skunks" }
, { "slith", "slith" }
, { "sliver", "slivers" }
, { "sloth", "sloths" }
, { "slug", "slugs" }
, { "snail", "snails" }
, { "snake", "snakes" }
, { "soldier", "soldiers" }
, { "soltari", "soltari" }
, { "sorcerer", "sorcerers" }
, { "spawn", "spawns" }
, { "specter", "specters" }
, { "spellshaper", "spellshapers" }
, { "sphinx", "sphinxes" }
, { "spider", "spiders" }
, { "spike", "spikes" }
, { "spirit", "spirits" }
, { "splinter", "splinters" }
, { "sponge", "sponges" }
, { "spy", "spies" }
, { "squid", "squids" }
, { "squirrel", "squirrels" }
, { "starfish", "starfish" }
, { "surrakar", "surrakar" }
, { "survivor", "survivors" }
, { "symbiote", "symbiotes" }
, { "synth", "synths" }
, { "tentacle", "tentacles" }
, { "tetravite", "tetravites" }
, { "thalakos", "thalakos" }
, { "thopter", "thopters" }
, { "thrull", "thrulls" }
, { "tiefling", "tieflings" }
, { "time lord", "time lords" }
, { "toy", "toys" }
, { "treefolk", "treefolk" }
, { "trilobite", "trilobites" }
, { "triskelavite", "triskelavites" }
, { "troll", "trolls" }
, { "turtle", "turtles" }
, { "tyranid", "tyranids" }
, { "unicorn", "unicorns" }
, { "utrom", "utrom" }
, { "vampire", "vampires" }
, { "varmint", "varmints" }
, { "vedalken", "vedalken" }
, { "villain", "villains" }
, { "volver", "volvers" }
, { "wall", "walls" }
, { "walrus", "walruses" }
, { "warlock", "warlocks" }
, { "warrior", "warriors" }
, { "weasel", "weasels" }
, { "weird", "weirds" }
, { "werewolf", "werewolves" }
, { "whale", "whales" }
, { "wizard", "wizards" }
, { "wolf", "wolves" }
, { "wolverine", "wolverines" }
, { "wombat", "wombats" }
, { "worm", "worms" }
, { "wraith", "wraiths" }
, { "wurm", "wurms" }
, { "yeti", "yeti" }
, { "zombie", "zombies" }
, { "zubera", "zubera" }
, { "alicorn", "alicorns" }
, { "armored", "armored" }
, { "art", "arts" }
, { "artist", "artists" }
, { "athlete", "athletes" }
, { "attendee", "attendees" }
, { "autobot", "autobots" }
, { "aven", "aven" }
, { "boxer", "boxers" }
, { "brainiac", "brainiacs" }
, { "bureaucrat", "bureaucrats" }
, { "chameleon", "chameleons" }
, { "champion", "champions" }
, { "chef", "chefs" }
, { "chicken", "chickens" }
, { "clamfolk", "clamfolk" }
, { "cow", "cows" }
, { "cyborg", "cyborgs" }
, { "deer", "deer" }
, { "designer", "designers" }
, { "die", "dice" }
, { "donkey", "donkeys" }
, { "elemental?", "elementals?" }
, { "elves", "elves" }
, { "expansion-symbol", "expansion-symbols" }
, { "fan", "fans" }
, { "fighter", "fighters" }
, { "glass", "glass" }
, { "gorilla", "gorillas" }
, { "grandchild", "grandchildren" }
, { "gus", "gus" }
, { "half", "halves" }
, { "hatificer", "hatificers" }
, { "hawk", "hawks" }
, { "head", "heads" }
, { "human?", "humans?" }
, { "jaguar", "jaguars" }
, { "judge", "judges" }
, { "killbot", "killbots" }
, { "lady of proper etiquette", "ladies of proper etiquette" }
, { "locus", "loci" }
, { "mammoth", "mammoths" }
, { "mime", "mimes" }
, { "mummy", "mummies" }
, { "paratrooper", "paratroopers" }
, { "penguin", "penguins" }
, { "pony", "ponies" }
, { "present", "presents" }
, { "reveler", "revelers" }
, { "ship", "ships" }
, { "sketch", "sketches" }
, { "spuzzem", "spuzzem" }
, { "spy", "spies" }
, { "stained", "stained" }
, { "teddy", "teddies" }
, { "the biggest, baddest, nastiest, scariest creature you'll ever see", "the biggest, baddest, nastiest, scariest creatures you'll ever see" }
, { "townsfolk", "townsfolk" }
, { "tree", "trees" }
, { "vampyre", "vampyres" }
, { "waiter", "waiters" }
, { "windmill", "windmills" }
, { "wrestler", "wrestlers" }
, { "zonian", "zonians" }
};
inline std::unordered_map<wxString, wxString> english_singular_exceptions {
{ "plains", "plains" }
, { "advisors", "advisor" }
, { "aetherborn", "aetherborn" }
, { "aliens", "alien" }
, { "allies", "ally" }
, { "angels", "angel" }
, { "antelopes", "antelope" }
, { "apes", "ape" }
, { "archers", "archer" }
, { "archons", "archon" }
, { "armadillos", "armadillo" }
, { "armies", "army" }
, { "artificers", "artificer" }
, { "assassins", "assassin" }
, { "assembly-workers", "assembly-worker" }
, { "astartes", "astartes" }
, { "atogs", "atog" }
, { "aurochs", "aurochs" }
, { "avatars", "avatar" }
, { "azra", "azra" }
, { "badgers", "badger" }
, { "balloons", "balloon" }
, { "barbarians", "barbarian" }
, { "bards", "bard" }
, { "basilisks", "basilisk" }
, { "bats", "bat" }
, { "bears", "bear" }
, { "beasts", "beast" }
, { "beavers", "beaver" }
, { "beebles", "beeble" }
, { "beholders", "beholder" }
, { "berserkers", "berserker" }
, { "birds", "bird" }
, { "bison", "bison" }
, { "blinkmoths", "blinkmoth" }
, { "boars", "boar" }
, { "bringers", "bringer" }
, { "brushwaggs", "brushwagg" }
, { "c'tan", "c'tan" }
, { "camarids", "camarid" }
, { "camels", "camel" }
, { "capybaras", "capybara" }
, { "caribou", "caribou" }
, { "carriers", "carrier" }
, { "cats", "cat" }
, { "centaurs", "centaur" }
, { "children", "child" }
, { "chimeras", "chimera" }
, { "citizens", "citizen" }
, { "clerics", "cleric" }
, { "clowns", "clown" }
, { "cockatrices", "cockatrice" }
, { "constructs", "construct" }
, { "cowards", "coward" }
, { "coyotes", "coyote" }
, { "crabs", "crab" }
, { "crocodiles", "crocodile" }
, { "custodes", "custodes" }
, { "cybermen", "cyberman" }
, { "cyclopes", "cyclops" }
, { "daleks", "dalek" }
, { "dauthi", "dauthi" }
, { "demigods", "demigod" }
, { "demons", "demon" }
, { "deserters", "deserter" }
, { "detectives", "detective" }
, { "devils", "devil" }
, { "dinosaurs", "dinosaur" }
, { "djinn", "djinn" }
, { "doctors", "doctor" }
, { "dogs", "dog" }
, { "dragons", "dragon" }
, { "drakes", "drake" }
, { "dreadnoughts", "dreadnought" }
, { "drix", "drix" }
, { "drones", "drone" }
, { "druids", "druid" }
, { "dryads", "dryad" }
, { "dwarves", "dwarf" }
, { "echdnas", "echidna" }
, { "efreets", "efreet" }
, { "eggs", "egg" }
, { "elders", "elder" }
, { "eldrazi", "eldrazi" }
, { "elementals", "elemental" }
, { "elephants", "elephant" }
, { "elves", "elf" }
, { "elk", "elk" }
, { "employees", "employee" }
, { "eternals", "eternal" }
, { "eyes", "eye" }
, { "faeries", "faerie" }
, { "ferrets", "ferret" }
, { "fish", "fish" }
, { "flagbearers", "flagbearer" }
, { "foxes", "fox" }
, { "fractals", "fractal" }
, { "frogs", "frog" }
, { "fungi", "fungus" }
, { "gamers", "gamer" }
, { "gamma mutates", "gamma" }
, { "gargoyles", "gargoyle" }
, { "germs", "germ" }
, { "giants", "giant" }
, { "giraffes", "giraffe" }
, { "gith", "gith" }
, { "glimmers", "glimmer" }
, { "gnolls", "gnoll" }
, { "gnomes", "gnome" }
, { "goats", "goat" }
, { "goblins", "goblin" }
, { "gods", "god" }
, { "golems", "golem" }
, { "gorgons", "gorgon" }
, { "graveborn", "graveborn" }
, { "gremlins", "gremlin" }
, { "griffins", "griffin" }
, { "guests", "guest" }
, { "hags", "hag" }
, { "halflings", "halfling" }
, { "hamsters", "hamster" }
, { "harpies", "harpy" }
, { "hedgehogs", "hedgehog" }
, { "hellions", "hellion" }
, { "heroes", "hero" }
, { "hippos", "hippo" }
, { "hippogriffs", "hippogriff" }
, { "homarids", "homarid" }
, { "homunculi", "homunculus" }
, { "horrors", "horror" }
, { "horses", "horse" }
, { "humans", "human" }
, { "hydras", "hydra" }
, { "hyenas", "hyena" }
, { "illusions", "illusion" }
, { "imps", "imp" }
, { "incarnations", "incarnation" }
, { "inklings", "inkling" }
, { "inquisitors", "inquisitor" }
, { "insects", "insect" }
, { "jackals", "jackal" }
, { "jellyfish", "jellyfish" }
, { "juggernauts", "juggernaut" }
, { "kangaroos", "kangaroo" }
, { "kavu", "kavu" }
, { "kirin", "kirin" }
, { "kithkin", "kithkin" }
, { "knights", "knight" }
, { "kobolds", "kobold" }
, { "kor", "kor" }
, { "krakens", "kraken" }
, { "lamia", "lamia" }
, { "lammasu", "lammasu" }
, { "leeches", "leech" }
, { "lemurs", "lemur" }
, { "leviathans", "leviathan" }
, { "lhurgoyfs", "lhurgoyf" }
, { "licids", "licid" }
, { "lizards", "lizard" }
, { "llamas", "llama" }
, { "lobsters", "lobster" }
, { "manticores", "manticore" }
, { "masticores", "masticore" }
, { "mercenaries", "mercenary" }
, { "merfolk", "merfolk" }
, { "metathran", "metathran" }
, { "minions", "minion" }
, { "minotaurs", "minotaur" }
, { "mites", "mite" }
, { "moles", "mole" }
, { "mongers", "monger" }
, { "mongooses", "mongoose" }
, { "monks", "monk" }
, { "monkeys", "monkey" }
, { "moogles", "moogle" }
, { "moonfolk", "moonfolk" }
, { "mounts", "mount" }
, { "mice", "mouse" }
, { "mutants", "mutant" }
, { "myr", "myr" }
, { "mystics", "mystic" }
, { "nautiluses", "nautilus" }
, { "necrons", "necron" }
, { "nephilim", "nephilim" }
, { "nightmares", "nightmare" }
, { "nightstalkers", "nightstalker" }
, { "ninja", "ninja" }
, { "nobles", "noble" }
, { "noggles", "noggle" }
, { "nomads", "nomad" }
, { "nymphs", "nymph" }
, { "octopuses", "octopus" }
, { "ogres", "ogre" }
, { "oozes", "ooze" }
, { "orbs", "orb" }
, { "orcs", "orc" }
, { "orggs", "orgg" }
, { "otters", "otter" }
, { "ouphes", "ouphe" }
, { "oxen", "ox" }
, { "oysters", "oyster" }
, { "pangolins", "pangolin" }
, { "peasants", "peasant" }
, { "pegasi", "pegasus" }
, { "pentavites", "pentavite" }
, { "performers", "performer" }
, { "pests", "pest" }
, { "phelddagrifs", "phelddagrif" }
, { "phoenixes", "phoenix" }
, { "phyrexians", "phyrexian" }
, { "pilots", "pilot" }
, { "pinchers", "pincher" }
, { "pirates", "pirate" }
, { "plants", "plant" }
, { "platypuses", "platypus" }
, { "porcupines", "porcupine" }
, { "possums", "possum" }
, { "praetors", "praetor" }
, { "primarchs", "primarch" }
, { "prisms", "prism" }
, { "processors", "processor" }
, { "qu", "qu" }
, { "rabbits", "rabbit" }
, { "raccoons", "raccoon" }
, { "rangers", "ranger" }
, { "rats", "rat" }
, { "rebels", "rebel" }
, { "reflections", "reflection" }
, { "rhinos", "rhino" }
, { "riggers", "rigger" }
, { "robots", "robot" }
, { "rogues", "rogue" }
, { "sables", "sable" }
, { "salamanders", "salamander" }
, { "samurai", "samurai" }
, { "sands", "sand" }
, { "saprolings", "saproling" }
, { "satyrs", "satyr" }
, { "scarecrows", "scarecrow" }
, { "scientists", "scientist" }
, { "scions", "scion" }
, { "scorpions", "scorpion" }
, { "scouts", "scout" }
, { "sculptures", "sculpture" }
, { "seals", "seal" }
, { "serfs", "serf" }
, { "serpents", "serpent" }
, { "servos", "servo" }
, { "shades", "shade" }
, { "shamans", "shaman" }
, { "shapeshifters", "shapeshifter" }
, { "sharks", "shark" }
, { "sheep", "sheep" }
, { "sirens", "siren" }
, { "skeletons", "skeleton" }
, { "skrulls", "skrull" }
, { "skunks", "skunk" }
, { "slith", "slith" }
, { "slivers", "sliver" }
, { "sloths", "sloth" }
, { "slugs", "slug" }
, { "snails", "snail" }
, { "snakes", "snake" }
, { "soldiers", "soldier" }
, { "soltari", "soltari" }
, { "sorcerers", "sorcerer" }
, { "spawns", "spawn" }
, { "specters", "specter" }
, { "spellshapers", "spellshaper" }
, { "sphinxes", "sphinx" }
, { "spiders", "spider" }
, { "spikes", "spike" }
, { "spirits", "spirit" }
, { "splinters", "splinter" }
, { "sponges", "sponge" }
, { "spies", "spy" }
, { "squids", "squid" }
, { "squirrels", "squirrel" }
, { "starfish", "starfish" }
, { "surrakar", "surrakar" }
, { "survivors", "survivor" }
, { "symbiotes", "symbiote" }
, { "synths", "synth" }
, { "tentacles", "tentacle" }
, { "tetravites", "tetravite" }
, { "thalakos", "thalakos" }
, { "thopters", "thopter" }
, { "thrulls", "thrull" }
, { "tieflings", "tiefling" }
, { "time lords", "time lord" }
, { "toys", "toy" }
, { "treefolk", "treefolk" }
, { "trilobites", "trilobite" }
, { "triskelavites", "triskelavite" }
, { "trolls", "troll" }
, { "turtles", "turtle" }
, { "tyranids", "tyranid" }
, { "unicorns", "unicorn" }
, { "utrom", "utrom" }
, { "vampires", "vampire" }
, { "varmints", "varmint" }
, { "vedalken", "vedalken" }
, { "villains", "villain" }
, { "volvers", "volver" }
, { "walls", "wall" }
, { "walruses", "walrus" }
, { "warlocks", "warlock" }
, { "warriors", "warrior" }
, { "weasels", "weasel" }
, { "weirds", "weird" }
, { "werewolves", "werewolf" }
, { "whales", "whale" }
, { "wizards", "wizard" }
, { "wolves", "wolf" }
, { "wolverines", "wolverine" }
, { "wombats", "wombat" }
, { "worms", "worm" }
, { "wraiths", "wraith" }
, { "wurms", "wurm" }
, { "yeti", "yeti" }
, { "zombies", "zombie" }
, { "zubera", "zubera" }
, { "alicorns", "alicorn" }
, { "armored", "armored" }
, { "arts", "art" }
, { "artists", "artist" }
, { "athletes", "athlete" }
, { "attendees", "attendee" }
, { "autobots", "autobot" }
, { "aven", "aven" }
, { "boxers", "boxer" }
, { "brainiacs", "brainiac" }
, { "bureaucrats", "bureaucrat" }
, { "chameleons", "chameleon" }
, { "champions", "champion" }
, { "chefs", "chef" }
, { "chickens", "chicken" }
, { "clamfolk", "clamfolk" }
, { "cows", "cow" }
, { "cyborgs", "cyborg" }
, { "deer", "deer" }
, { "designers", "designer" }
, { "dice", "die" }
, { "donkeys", "donkey" }
, { "elementals?", "elemental?" }
, { "elves", "elves" }
, { "expansion-symbols", "expansion-symbol" }
, { "fans", "fan" }
, { "fighters", "fighter" }
, { "glass", "glass" }
, { "gorillas", "gorilla" }
, { "grandchildren", "grandchild" }
, { "gus", "gus" }
, { "halves", "half" }
, { "hatificers", "hatificer" }
, { "hawks", "hawk" }
, { "heads", "head" }
, { "humans?", "human?" }
, { "jaguars", "jaguar" }
, { "judges", "judge" }
, { "killbots", "killbot" }
, { "ladies of proper etiquette", "lady of proper etiquette" }
, { "loci", "locus" }
, { "mammoths", "mammoth" }
, { "mimes", "mime" }
, { "mummies", "mummy" }
, { "paratroopers", "paratrooper" }
, { "penguins", "penguin" }
, { "ponies", "pony" }
, { "presents", "present" }
, { "revelers", "reveler" }
, { "ships", "ship" }
, { "sketches", "sketch" }
, { "spuzzem", "spuzzem" }
, { "spies", "spy" }
, { "stained", "stained" }
, { "teddies", "teddy" }
, { "the biggest, baddest, nastiest, scariest creatures you'll ever see", "the biggest, baddest, nastiest, scariest creature you'll ever see" }
, { "townsfolk", "townsfolk" }
, { "trees", "tree" }
, { "vampyres", "vampyre" }
, { "waiters", "waiter" }
, { "windmills", "windmill" }
, { "wrestlers", "wrestler" }
, { "zonians", "zonian" }
};
+18 -18
View File
@@ -51,15 +51,9 @@ SCRIPT_FUNCTION(to_card_image) {
}
SCRIPT_FUNCTION(import_image) {
SCRIPT_PARAM(Set*, set);
SCRIPT_PARAM_C(ScriptValueP, input);
if (input->type() == SCRIPT_IMAGE) {
return make_intrusive<ScriptedImage>(set, input->toImage());
}
else if (input->type() == SCRIPT_STRING) {
return make_intrusive<ImportedImage>(set, input->toString());
}
throw ScriptErrorConversion(input->typeName(), _TYPE_("image"));
SCRIPT_PARAM(Set*, set);
SCRIPT_PARAM(String, input);
return make_intrusive<ImportedImage>(set, input);
}
SCRIPT_FUNCTION(download_image) {
@@ -73,9 +67,9 @@ SCRIPT_FUNCTION(download_image) {
SCRIPT_FUNCTION(get_metadata) {
SCRIPT_PARAM(Set*, set);
SCRIPT_PARAM(GeneratedImageP, input);
Image image = input->generate(GeneratedImage::Options(0, 0, set, set));
SCRIPT_RETURN(image.GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION));
SCRIPT_PARAM(GeneratedImageP, input);
Image img = input->generate(GeneratedImage::Options(0, 0, set));
SCRIPT_RETURN(img.GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION));
}
SCRIPT_FUNCTION(set_metadata) {
@@ -87,22 +81,28 @@ SCRIPT_FUNCTION(set_metadata) {
SCRIPT_FUNCTION(width_of) {
SCRIPT_PARAM(Set*, set);
SCRIPT_PARAM(GeneratedImageP, input);
Image image = input->generate(GeneratedImage::Options(0, 0, set, set));
SCRIPT_PARAM(CardP, card);
SCRIPT_PARAM(GeneratedImageP, input);
StyleSheet* stylesheet = card && card->stylesheet ? card->stylesheet.get() : set->stylesheet.get();
Image image = input->generate(GeneratedImage::Options(0, 0, stylesheet));
SCRIPT_RETURN(image.GetWidth());
}
SCRIPT_FUNCTION(height_of) {
SCRIPT_PARAM(Set*, set);
SCRIPT_PARAM(GeneratedImageP, input);
Image image = input->generate(GeneratedImage::Options(0, 0, set, set));
SCRIPT_PARAM(CardP, card);
SCRIPT_PARAM(GeneratedImageP, input);
StyleSheet* stylesheet = card && card->stylesheet ? card->stylesheet.get() : set->stylesheet.get();
Image image = input->generate(GeneratedImage::Options(0, 0, stylesheet));
SCRIPT_RETURN(image.GetHeight());
}
SCRIPT_FUNCTION(dimensions_of) {
SCRIPT_PARAM(Set*, set);
SCRIPT_PARAM(GeneratedImageP, input);
Image image = input->generate(GeneratedImage::Options(0, 0, set, set));
SCRIPT_PARAM(CardP, card);
SCRIPT_PARAM(GeneratedImageP, input);
StyleSheet* stylesheet = card && card->stylesheet ? card->stylesheet.get() : set->stylesheet.get();
Image image = input->generate(GeneratedImage::Options(0, 0, stylesheet));
ScriptCustomCollectionP ret(new ScriptCustomCollection());
ret->value.push_back(to_script(image.GetWidth()));
ret->value.push_back(to_script(image.GetHeight()));
+266 -296
View File
@@ -112,25 +112,13 @@ void pretty_print(std::ostream& os, const boost::json::value& jv, std::string* i
String json_pretty_print(const boost::json::value& jv, std::string* indent) {
std::ostringstream stream;
pretty_print(stream, jv, indent);
std::string stdstring = stream.str();
const char* data = stdstring.data();
size_t size = stdstring.size();
String wxstring = String::FromUTF8(data, size);
if (wxstring.empty() && size > 0) {
wxstring = String(data, wxConvWhateverWorks, size);
}
return wxstring;
String string = wxString(stream.str().c_str());
return string;
}
String json_ugly_print(const boost::json::value& jv) {
std::string stdstring = boost::json::serialize(jv);
const char* data = stdstring.data();
size_t size = stdstring.size();
String wxstring = String::FromUTF8(data, size);
if (wxstring.empty() && size > 0) {
wxstring = String(data, wxConvWhateverWorks, size);
}
return wxstring;
String string = wxString(boost::json::serialize(jv).c_str());
return string;
}
// ----------------------------------------------------------------------------- : JSON to MSE
@@ -140,33 +128,23 @@ ScriptValueP json_to_mse(const boost::json::value& jv, Set* set);
template <typename T>
void read(T& out, boost::json::object& jv, const char value_name[]) {
if (!jv.contains(value_name)) return;
boost::json::string jstring = jv[value_name].as_string();
const char* data = jstring.data();
size_t size = jstring.size();
String wxstring = String::FromUTF8(data, size);
if (wxstring.empty() && size > 0) {
wxstring = String(data, wxConvWhateverWorks, size);
else {
wxStringInputStream stream = {_("")};
Reader reader(stream, nullptr, _(""));
reader.setValue(wxString(jv[value_name].as_string().c_str()));
reader.handle(out);
}
wxStringInputStream stream(wxstring);
Reader reader(stream, nullptr, _(""), false, true);
reader.setValue(wxstring);
reader.handle(out);
}
// templates don't work with enums? are you kidding me with this language?
void read(PackSelectType& out, boost::json::object& jv, const char value_name[]) {
if (!jv.contains(value_name)) return;
boost::json::string jstring = jv[value_name].as_string();
const char* data = jstring.data();
size_t size = jstring.size();
String wxstring = String::FromUTF8(data, size);
if (wxstring.empty() && size > 0) {
wxstring = String(data, wxConvWhateverWorks, size);
else {
wxStringInputStream stream = {_("")};
Reader reader(stream, nullptr, _(""));
reader.setValue(wxString(jv[value_name].as_string().c_str()));
reader.handle(out);
}
wxStringInputStream stream(wxstring);
Reader reader(stream, nullptr, _(""), false, true);
reader.setValue(wxstring);
reader.handle(out);
}
PackItemP json_to_mse_pack_item(boost::json::object& jv) {
@@ -185,7 +163,7 @@ PackTypeP json_to_mse_pack_type(boost::json::object& jv) {
read(pack_type->summary, jv, "summary");
read(pack_type->select, jv, "select");
if (jv.contains("items") && jv["items"].is_array()) {
boost::json::array pack_itemsv = jv["items"].get_array();
boost::json::array pack_itemsv = jv["items"].as_array();
for (size_t i = 0; i < pack_itemsv.size(); i++) {
boost::json::object pack_itemv = pack_itemsv[i].as_object();
pack_type->items.emplace_back(json_to_mse_pack_item(pack_itemv));
@@ -206,43 +184,38 @@ KeywordP json_to_mse_keyword(boost::json::object& jv) {
CardP json_to_mse_card(boost::json::object& jv, Set* set) {
CardP card = make_intrusive<Card>(*set->game);
read(card->time_created, jv, "time_created");
read(card->time_modified, jv, "time_modified");
read(card->notes, jv, "notes");
read(card->uid, jv, "uid");
read(card->linked_card_1, jv, "linked_card_1");
read(card->linked_card_2, jv, "linked_card_2");
read(card->linked_card_3, jv, "linked_card_3");
read(card->linked_card_4, jv, "linked_card_4");
read(card->linked_relation_1, jv, "linked_relation_1");
read(card->linked_relation_2, jv, "linked_relation_2");
read(card->linked_relation_3, jv, "linked_relation_3");
read(card->linked_relation_4, jv, "linked_relation_4");
read(card->time_created, jv, "time_created");
read(card->time_modified, jv, "time_modified");
read(card->notes, jv, "notes");
read(card->uid, jv, "uid");
read(card->linked_card_1, jv, "linked_card_1");
read(card->linked_card_2, jv, "linked_card_2");
read(card->linked_card_3, jv, "linked_card_3");
read(card->linked_card_4, jv, "linked_card_4");
read(card->linked_relation_1, jv, "linked_relation_1");
read(card->linked_relation_2, jv, "linked_relation_2");
read(card->linked_relation_3, jv, "linked_relation_3");
read(card->linked_relation_4, jv, "linked_relation_4");
// card fields
if (jv.contains("data") && jv["data"].is_object()) {
boost::json::object datav = jv["data"].get_object();
boost::json::object datav = jv["data"].as_object();
for (auto it = datav.begin(); it != datav.end(); ++it) {
boost::json::string_view key_view = it->key();
String key_name = String::FromUTF8(key_view.data(), key_view.size());
String key_name = wxString(it->key_c_str());
Value* container = get_card_field_container(*set->game, card->data, key_name, false);
ScriptValueP value = json_to_mse(it->value(), set);
set_container(container, value, key_name);
}
}
// stylesheet
if (jv.contains("stylesheet")) {
boost::json::string stylesheet_name = jv["stylesheet"].as_string();
card->stylesheet = StyleSheet::byGameAndName(*set->game, String::FromUTF8(stylesheet_name.data(), stylesheet_name.size()));
}
if (jv.contains("stylesheet")) card->stylesheet = StyleSheet::byGameAndName(*set->game, wxString(jv["stylesheet"].as_string().c_str()));
if (card->stylesheet) {
// styling fields
card->styling_data.init(card->stylesheet->styling_fields);
if (jv.contains("styling_data") && jv["styling_data"].is_object()) {
boost::json::object datav = jv["styling_data"].get_object();
boost::json::object datav = jv["styling_data"].as_object();
for (auto it = datav.begin(); it != datav.end(); ++it) {
boost::json::string_view key_view = it->key();
String key_name = String::FromUTF8(key_view.data(), key_view.size());
Value* container = get_container(card->styling_data, String("styling"), key_name, false);
String key_name = wxString(it->key_c_str());
Value* container = get_container(card->styling_data, wxString("styling"), key_name, false);
ScriptValueP value = json_to_mse(it->value(), set);
set_container(container, value, key_name);
card->has_styling = true;
@@ -250,18 +223,15 @@ CardP json_to_mse_card(boost::json::object& jv, Set* set) {
}
// extra card fields
if (jv.contains("extra_data") && jv["extra_data"].is_object()) {
boost::json::object datav = jv["extra_data"].get_object();
boost::json::object datav = jv["extra_data"].as_object();
for (auto it = datav.begin(); it != datav.end(); ++it) {
boost::json::string_view stylesheet_view = it->key();
StyleSheetP stylesheet = StyleSheet::byGameAndName(*set->game, String::FromUTF8(stylesheet_view.data(), stylesheet_view.size()));
StyleSheetP stylesheet = StyleSheet::byGameAndName(*set->game, it->key_c_str());
if (!stylesheet) continue;
IndexMap<FieldP, ValueP>& stylesheet_data = card->extraDataFor(*stylesheet);
stylesheet_data.init(stylesheet->extra_card_fields);
boost::json::object stylesheet_datav = it->value().as_object();
for (auto stylesheet_it = stylesheet_datav.begin(); stylesheet_it != stylesheet_datav.end(); ++stylesheet_it) {
boost::json::string_view key_view = stylesheet_it->key();
String key_name = String::FromUTF8(key_view.data(), key_view.size());
Value* container = get_container(stylesheet_data, String("extra card"), key_name, false);
String key_name = wxString(stylesheet_it->key_c_str());
Value* container = get_container(stylesheet_data, wxString("extra card"), key_name, false);
ScriptValueP value = json_to_mse(stylesheet_it->value(), set);
set_container(container, value, key_name);
}
@@ -278,35 +248,30 @@ SetP json_to_mse_set(boost::json::object& jv) {
if (!jv.contains("stylesheet")) {
throw ScriptError(_ERROR_("json set without stylesheet"));
}
boost::json::string game_name = jv["game"].as_string();
GameP game = Game::byName(String::FromUTF8(game_name.data(), game_name.size()));
boost::json::string stylesheet_name = jv["stylesheet"].as_string();
StyleSheetP stylesheet = StyleSheet::byGameAndName(*game, String::FromUTF8(stylesheet_name.data(), stylesheet_name.size()));
GameP game = Game::byName(wxString(jv["game"].as_string().c_str()));
StyleSheetP stylesheet = StyleSheet::byGameAndName(*game, wxString(jv["stylesheet"].as_string().c_str()));
SetP set = make_intrusive<Set>(stylesheet);
// set fields
if (jv.contains("set_info") && jv["set_info"].is_object()) {
boost::json::object datav = jv["set_info"].get_object();
boost::json::object datav = jv["set_info"].as_object();
for (auto it = datav.begin(); it != datav.end(); ++it) {
boost::json::string_view key_view = it->key();
String key_name = String::FromUTF8(key_view.data(), key_view.size());
Value* container = get_container(set->data, String("set"), key_name, false);
String key_name = wxString(it->key_c_str());
Value* container = get_container(set->data, wxString("set"), key_name, false);
ScriptValueP value = json_to_mse(it->value(), set.get());
set_container(container, value, key_name);
}
}
// styling
if (jv.contains("styling") && jv["styling"].is_object()) {
boost::json::object datav = jv["styling"].get_object();
boost::json::object datav = jv["styling"].as_object();
for (auto it = datav.begin(); it != datav.end(); ++it) {
boost::json::string_view stylesheet_view = it->key();
StyleSheetP stylesheet = StyleSheet::byGameAndName(*set->game, String::FromUTF8(stylesheet_view.data(), stylesheet_view.size()));
StyleSheetP stylesheet = StyleSheet::byGameAndName(*set->game, it->key_c_str());
if (!stylesheet) continue;
IndexMap<FieldP, ValueP>& stylesheet_data = set->stylingDataFor(*stylesheet);
boost::json::object stylesheet_datav = it->value().as_object();
for (auto stylesheet_it = stylesheet_datav.begin(); stylesheet_it != stylesheet_datav.end(); ++stylesheet_it) {
boost::json::string_view key_view = stylesheet_it->key();
String key_name = String::FromUTF8(key_view.data(), key_view.size());
Value* container = get_container(stylesheet_data, String("styling"), key_name, false);
String key_name = wxString(stylesheet_it->key_c_str());
Value* container = get_container(stylesheet_data, wxString("styling"), key_name, false);
ScriptValueP value = json_to_mse(stylesheet_it->value(), set.get());
set_container(container, value, key_name);
}
@@ -314,7 +279,7 @@ SetP json_to_mse_set(boost::json::object& jv) {
}
// cards
if (jv.contains("cards") && jv["cards"].is_array()) {
boost::json::array cardsv = jv["cards"].get_array();
boost::json::array cardsv = jv["cards"].as_array();
for (size_t i = 0; i < cardsv.size(); i++) {
boost::json::object cardv = cardsv[i].as_object();
set->cards.emplace_back(json_to_mse_card(cardv, set.get()));
@@ -322,7 +287,7 @@ SetP json_to_mse_set(boost::json::object& jv) {
}
// keywords
if (jv.contains("keywords") && jv["keywords"].is_array()) {
boost::json::array keywordsv = jv["keywords"].get_array();
boost::json::array keywordsv = jv["keywords"].as_array();
for (size_t i = 0; i < keywordsv.size(); i++) {
boost::json::object keywordv = keywordsv[i].as_object();
set->keywords.emplace_back(json_to_mse_keyword(keywordv));
@@ -330,7 +295,7 @@ SetP json_to_mse_set(boost::json::object& jv) {
}
// pack types
if (jv.contains("pack_types") && jv["pack_types"].is_array()) {
boost::json::array pack_typesv = jv["pack_types"].get_array();
boost::json::array pack_typesv = jv["pack_types"].as_array();
for (size_t i = 0; i < pack_typesv.size(); i++) {
boost::json::object pack_typev = pack_typesv[i].as_object();
set->pack_types.emplace_back(json_to_mse_pack_type(pack_typev));
@@ -353,13 +318,17 @@ ScriptValueP json_to_mse(const boost::json::value& jv, Set* set) {
return to_script(integer);
}
else if (jv.is_string()) {
boost::json::string jstring = jv.get_string();
if (jstring.empty()) return to_script(String());
const char* data = jstring.data();
size_t size = jstring.size();
String wxstring = String::FromUTF8(data, size);
if (jv.as_string().empty()) return to_script(String());
std::string string = boost::json::value_to<std::string>(jv);
const char* cstring = string.c_str();
size_t nulpos = strlen(cstring);
// if the string contains nul bytes, we have to use the std::string constructor, even though we can't specify the encoding
if (nulpos < string.size()) return to_script(String(string));
// if the string doesn't contain nul bytes, we can use the constructor that allows to specify the encoding
String wxstring(cstring, wxConvUTF8);
if (!wxstring.empty()) return to_script(wxstring);
return to_script(String(data, wxConvWhateverWorks, size));
// if all else fails, use "Whatever Works"
return to_script(String(cstring, wxConvWhateverWorks));
}
else if (jv.is_array()) {
boost::json::array array = jv.get_array();
@@ -380,16 +349,18 @@ ScriptValueP json_to_mse(const boost::json::value& jv, Set* set) {
if (mse_object_type == "keyword") return make_intrusive<ScriptObject<KeywordP>> (json_to_mse_keyword(object));
if (mse_object_type == "pack_type") return make_intrusive<ScriptObject<PackTypeP>>(json_to_mse_pack_type(object));
if (mse_object_type == "pack_item") return make_intrusive<ScriptObject<PackItemP>>(json_to_mse_pack_item(object));
queue_message(MESSAGE_ERROR, _ERROR_("json unknown type") + _("(") + String(mse_object_type.c_str()) + _(")"));
queue_message(MESSAGE_ERROR, _ERROR_("json unknown type") + _("(") + wxString(mse_object_type.c_str()) + _(")"));
return script_nil;
}
ScriptCustomCollectionP result = make_intrusive<ScriptCustomCollection>();
for (auto it = object.begin(); it != object.end(); ++it) {
boost::json::string_view jview = it->key();
String key_name = String::FromUTF8(jview.data(), jview.size());
std::string_view stdview = std::string_view(jview.data(), jview.size());
std::string stdstring = { stdview.begin(), stdview.end() };
String key(stdstring.c_str(), wxConvUTF8);
boost::json::value jvalue = it->value();
ScriptValueP value = json_to_mse(jvalue, set);
result->key_value[key_name] = value;
result->key_value[key] = value;
}
return result;
}
@@ -403,9 +374,8 @@ ScriptValueP json_to_mse(const String& string, Set* set) {
boost::system::error_code ec;
boost::json::parse_options options;
options.allow_invalid_utf8 = true;
wxScopedCharBuffer buffer = string.ToUTF8();
boost::json::value jv = boost::json::parse(boost::json::string_view(buffer.data(), buffer.length()), ec, {}, options);
//if(ec && buffer.length() > 0) queue_message(MESSAGE_ERROR, _ERROR_("json cant parse") + _("\n\n") + ec.message());
boost::json::value jv = boost::json::parse(string.ToStdString(), ec, {}, options);
//if(ec) queue_message(MESSAGE_ERROR, _ERROR_("json cant parse") + _("\n\n") + ec.message());
if(ec) return script_nil;
return json_to_mse(jv, set);
}
@@ -542,92 +512,92 @@ boost::json::object mse_to_json(const StyleP& style) {
boost::json::object stylev;
stylev.emplace("mse_object_type", "style");
stylev.emplace("z_index", String::Format(wxT("%i"), style->z_index));
stylev.emplace("tab_index", String::Format(wxT("%i"), style->tab_index));
stylev.emplace("left", String::Format(wxT("%.2f"), style->left()));
stylev.emplace("top", String::Format(wxT("%.2f"), style->top()));
stylev.emplace("right", String::Format(wxT("%.2f"), style->right()));
stylev.emplace("bottom", String::Format(wxT("%.2f"), style->bottom()));
stylev.emplace("width", String::Format(wxT("%.2f"), style->width()));
stylev.emplace("height", String::Format(wxT("%.2f"), style->height()));
stylev.emplace("angle", String::Format(wxT("%.2f"), style->angle()));
stylev.emplace("visible", style->visible());
stylev.emplace("mask", style->mask.toScriptString());
stylev.emplace("z_index", wxString::Format(wxT("%i"), style->z_index));
stylev.emplace("tab_index", wxString::Format(wxT("%i"), style->tab_index));
stylev.emplace("left", wxString::Format(wxT("%.2f"), style->left()));
stylev.emplace("top", wxString::Format(wxT("%.2f"), style->top()));
stylev.emplace("right", wxString::Format(wxT("%.2f"), style->right()));
stylev.emplace("bottom", wxString::Format(wxT("%.2f"), style->bottom()));
stylev.emplace("width", wxString::Format(wxT("%.2f"), style->width()));
stylev.emplace("height", wxString::Format(wxT("%.2f"), style->height()));
stylev.emplace("angle", wxString::Format(wxT("%.2f"), style->angle()));
stylev.emplace("visible", style->visible());
stylev.emplace("mask", style->mask.toScriptString());
if (TextStyle* s = dynamic_cast<TextStyle*>(style.get())) {
stylev.emplace("field_type", "text");
boost::json::object fontv;
fontv.emplace("name", s->font.name());
fontv.emplace("italic_name", s->font.italic_name());
fontv.emplace("size", String::Format(wxT("%.2f"), s->font.size()));
fontv.emplace("weight", s->font.weight());
fontv.emplace("style", s->font.style());
fontv.emplace("underline", s->font.underline());
fontv.emplace("strikethrough", s->font.strikethrough());
fontv.emplace("scale_down_to", String::Format(wxT("%.2f"), s->font.scale_down_to));
fontv.emplace("max_stretch", String::Format(wxT("%.2f"), s->font.max_stretch));
fontv.emplace("color", format_color( s->font.color()));
fontv.emplace("shadow_color", format_color( s->font.shadow_color()));
fontv.emplace("shadow_displacement_x", String::Format(wxT("%.2f"), s->font.shadow_displacement_x()));
fontv.emplace("shadow_displacement_y", String::Format(wxT("%.2f"), s->font.shadow_displacement_y()));
fontv.emplace("shadow_blur", String::Format(wxT("%.2f"), s->font.shadow_blur()));
fontv.emplace("stroke_color", format_color( s->font.stroke_color()));
fontv.emplace("stroke_radius", String::Format(wxT("%.2f"), s->font.stroke_radius()));
fontv.emplace("stroke_blur", String::Format(wxT("%.2f"), s->font.stroke_blur()));
fontv.emplace("separator_color", format_color( s->font.separator_color));
fontv.emplace("flags", String::Format(wxT("%i"), s->font.flags));
stylev.emplace("font", fontv);
fontv.emplace("name", s->font.name());
fontv.emplace("italic_name", s->font.italic_name());
fontv.emplace("size", wxString::Format(wxT("%.2f"), s->font.size()));
fontv.emplace("weight", s->font.weight());
fontv.emplace("style", s->font.style());
fontv.emplace("underline", s->font.underline());
fontv.emplace("strikethrough", s->font.strikethrough());
fontv.emplace("scale_down_to", wxString::Format(wxT("%.2f"), s->font.scale_down_to));
fontv.emplace("max_stretch", wxString::Format(wxT("%.2f"), s->font.max_stretch));
fontv.emplace("color", format_color( s->font.color()));
fontv.emplace("shadow_color", format_color( s->font.shadow_color()));
fontv.emplace("shadow_displacement_x", wxString::Format(wxT("%.2f"), s->font.shadow_displacement_x()));
fontv.emplace("shadow_displacement_y", wxString::Format(wxT("%.2f"), s->font.shadow_displacement_y()));
fontv.emplace("shadow_blur", wxString::Format(wxT("%.2f"), s->font.shadow_blur()));
fontv.emplace("stroke_color", format_color( s->font.stroke_color()));
fontv.emplace("stroke_radius", wxString::Format(wxT("%.2f"), s->font.stroke_radius()));
fontv.emplace("stroke_blur", wxString::Format(wxT("%.2f"), s->font.stroke_blur()));
fontv.emplace("separator_color", format_color( s->font.separator_color));
fontv.emplace("flags", wxString::Format(wxT("%i"), s->font.flags));
stylev.emplace("font", fontv);
boost::json::object symbolfontv;
symbolfontv.emplace("name", s->symbol_font.name());
symbolfontv.emplace("size", String::Format(wxT("%.2f"), s->symbol_font.size()));
symbolfontv.emplace("underline", s->symbol_font.underline());
symbolfontv.emplace("strikethrough", s->symbol_font.strikethrough());
symbolfontv.emplace("scale_down_to", String::Format(wxT("%.2f"), s->symbol_font.scale_down_to));
symbolfontv.emplace("shadow_color", format_color( s->symbol_font.shadow_color()));
symbolfontv.emplace("shadow_displacement_x", String::Format(wxT("%.2f"), s->symbol_font.shadow_displacement_x()));
symbolfontv.emplace("shadow_displacement_y", String::Format(wxT("%.2f"), s->symbol_font.shadow_displacement_y()));
symbolfontv.emplace("shadow_blur", String::Format(wxT("%.2f"), s->symbol_font.shadow_blur()));
symbolfontv.emplace("stroke_color", format_color( s->symbol_font.stroke_color()));
symbolfontv.emplace("stroke_radius", String::Format(wxT("%.2f"), s->symbol_font.stroke_radius()));
symbolfontv.emplace("stroke_blur", String::Format(wxT("%.2f"), s->symbol_font.stroke_blur()));
stylev.emplace("symbol_font", symbolfontv);
symbolfontv.emplace("name", s->symbol_font.name());
symbolfontv.emplace("size", wxString::Format(wxT("%.2f"), s->symbol_font.size()));
symbolfontv.emplace("underline", s->symbol_font.underline());
symbolfontv.emplace("strikethrough", s->symbol_font.strikethrough());
symbolfontv.emplace("scale_down_to", wxString::Format(wxT("%.2f"), s->symbol_font.scale_down_to));
symbolfontv.emplace("shadow_color", format_color( s->symbol_font.shadow_color()));
symbolfontv.emplace("shadow_displacement_x", wxString::Format(wxT("%.2f"), s->symbol_font.shadow_displacement_x()));
symbolfontv.emplace("shadow_displacement_y", wxString::Format(wxT("%.2f"), s->symbol_font.shadow_displacement_y()));
symbolfontv.emplace("shadow_blur", wxString::Format(wxT("%.2f"), s->symbol_font.shadow_blur()));
symbolfontv.emplace("stroke_color", format_color( s->symbol_font.stroke_color()));
symbolfontv.emplace("stroke_radius", wxString::Format(wxT("%.2f"), s->symbol_font.stroke_radius()));
symbolfontv.emplace("stroke_blur", wxString::Format(wxT("%.2f"), s->symbol_font.stroke_blur()));
stylev.emplace("symbol_font", symbolfontv);
stylev.emplace("always_symbol", s->always_symbol);
stylev.emplace("allow_formating", s->allow_formating);
stylev.emplace("alignment", alignment_to_string( s->alignment()));
stylev.emplace("direction", direction_to_string( s->direction));
stylev.emplace("padding_left", String::Format(wxT("%.2f"), s->padding_left()));
stylev.emplace("padding_right", String::Format(wxT("%.2f"), s->padding_right()));
stylev.emplace("padding_top", String::Format(wxT("%.2f"), s->padding_top()));
stylev.emplace("padding_bottom", String::Format(wxT("%.2f"), s->padding_bottom()));
stylev.emplace("padding_left_min", String::Format(wxT("%.2f"), s->padding_left_min()));
stylev.emplace("padding_right_min", String::Format(wxT("%.2f"), s->padding_right_min()));
stylev.emplace("padding_top_min", String::Format(wxT("%.2f"), s->padding_top_min()));
stylev.emplace("padding_bottom_min", String::Format(wxT("%.2f"), s->padding_bottom_min()));
stylev.emplace("line_height_soft", String::Format(wxT("%.2f"), s->line_height_soft()));
stylev.emplace("line_height_hard", String::Format(wxT("%.2f"), s->line_height_hard()));
stylev.emplace("line_height_line", String::Format(wxT("%.2f"), s->line_height_line()));
stylev.emplace("line_height_soft_max", String::Format(wxT("%.2f"), s->line_height_soft_max()));
stylev.emplace("line_height_hard_max", String::Format(wxT("%.2f"), s->line_height_hard_max()));
stylev.emplace("line_height_line_max", String::Format(wxT("%.2f"), s->line_height_line_max()));
stylev.emplace("paragraph_height", String::Format(wxT("%.2f"), s->paragraph_height()));
stylev.emplace("always_symbol", s->always_symbol);
stylev.emplace("allow_formating", s->allow_formating);
stylev.emplace("alignment", alignment_to_string( s->alignment()));
stylev.emplace("direction", direction_to_string( s->direction));
stylev.emplace("padding_left", wxString::Format(wxT("%.2f"), s->padding_left()));
stylev.emplace("padding_right", wxString::Format(wxT("%.2f"), s->padding_right()));
stylev.emplace("padding_top", wxString::Format(wxT("%.2f"), s->padding_top()));
stylev.emplace("padding_bottom", wxString::Format(wxT("%.2f"), s->padding_bottom()));
stylev.emplace("padding_left_min", wxString::Format(wxT("%.2f"), s->padding_left_min()));
stylev.emplace("padding_right_min", wxString::Format(wxT("%.2f"), s->padding_right_min()));
stylev.emplace("padding_top_min", wxString::Format(wxT("%.2f"), s->padding_top_min()));
stylev.emplace("padding_bottom_min", wxString::Format(wxT("%.2f"), s->padding_bottom_min()));
stylev.emplace("line_height_soft", wxString::Format(wxT("%.2f"), s->line_height_soft()));
stylev.emplace("line_height_hard", wxString::Format(wxT("%.2f"), s->line_height_hard()));
stylev.emplace("line_height_line", wxString::Format(wxT("%.2f"), s->line_height_line()));
stylev.emplace("line_height_soft_max", wxString::Format(wxT("%.2f"), s->line_height_soft_max()));
stylev.emplace("line_height_hard_max", wxString::Format(wxT("%.2f"), s->line_height_hard_max()));
stylev.emplace("line_height_line_max", wxString::Format(wxT("%.2f"), s->line_height_line_max()));
stylev.emplace("paragraph_height", wxString::Format(wxT("%.2f"), s->paragraph_height()));
boost::json::object layoutv;
layoutv.emplace("content_top", String::Format(wxT("%.2f"), s->layout->top));
layoutv.emplace("content_middle", String::Format(wxT("%.2f"), s->layout->middle()));
layoutv.emplace("content_bottom", String::Format(wxT("%.2f"), s->layout->bottom()));
layoutv.emplace("content_width", String::Format(wxT("%.2f"), s->layout->width));
layoutv.emplace("content_height", String::Format(wxT("%.2f"), s->layout->height));
layoutv.emplace("content_lines", String::Format(wxT("%i"), s->layout->lines.size()));
layoutv.emplace("content_clauses", String::Format(wxT("%i"), s->layout->clauses.size()));
layoutv.emplace("content_paragraphs", String::Format(wxT("%i"), s->layout->paragraphs.size()));
layoutv.emplace("content_blocks", String::Format(wxT("%i"), s->layout->blocks.size()));
layoutv.emplace("content_top", wxString::Format(wxT("%.2f"), s->layout->top));
layoutv.emplace("content_middle", wxString::Format(wxT("%.2f"), s->layout->middle()));
layoutv.emplace("content_bottom", wxString::Format(wxT("%.2f"), s->layout->bottom()));
layoutv.emplace("content_width", wxString::Format(wxT("%.2f"), s->layout->width));
layoutv.emplace("content_height", wxString::Format(wxT("%.2f"), s->layout->height));
layoutv.emplace("content_lines", wxString::Format(wxT("%i"), s->layout->lines.size()));
layoutv.emplace("content_clauses", wxString::Format(wxT("%i"), s->layout->clauses.size()));
layoutv.emplace("content_paragraphs", wxString::Format(wxT("%i"), s->layout->paragraphs.size()));
layoutv.emplace("content_blocks", wxString::Format(wxT("%i"), s->layout->blocks.size()));
boost::json::array separatorsv;
int size = s->layout->separators.size();
for (int i = 0; i < size; i++) {
separatorsv.emplace_back(String::Format(wxT("%.2f"), s->layout->separators[i]));
separatorsv.emplace_back(wxString::Format(wxT("%.2f"), s->layout->separators[i]));
}
if (size > 0) layoutv.emplace("content_separators", separatorsv);
@@ -642,35 +612,35 @@ boost::json::object mse_to_json(const StyleP& style) {
else if (MultipleChoiceStyle* s = dynamic_cast<MultipleChoiceStyle*>(style.get())) {
stylev.emplace("field_type", "multiple_choice");
stylev.emplace("popup_style", popup_style_to_string( s->popup_style));
stylev.emplace("render_style", render_style_to_string( s->render_style));
stylev.emplace("image", s->image.toScriptString());
stylev.emplace("combine", combine_to_string( s->combine));
stylev.emplace("alignment", alignment_to_string( s->alignment));
stylev.emplace("direction", direction_to_string( s->direction()));
stylev.emplace("spacing", String::Format(wxT("%.2f"), s->spacing()));
stylev.emplace("popup_style", popup_style_to_string( s->popup_style));
stylev.emplace("render_style", render_style_to_string( s->render_style));
stylev.emplace("image", s->image.toScriptString());
stylev.emplace("combine", combine_to_string( s->combine));
stylev.emplace("alignment", alignment_to_string( s->alignment));
stylev.emplace("direction", direction_to_string( s->direction()));
stylev.emplace("spacing", wxString::Format(wxT("%.2f"), s->spacing()));
boost::json::object fontv;
fontv.emplace("name", s->font.name());
fontv.emplace("italic_name", s->font.italic_name());
fontv.emplace("size", String::Format(wxT("%.2f"), s->font.size()));
fontv.emplace("weight", s->font.weight());
fontv.emplace("style", s->font.style());
fontv.emplace("underline", s->font.underline());
fontv.emplace("strikethrough", s->font.strikethrough());
fontv.emplace("scale_down_to", String::Format(wxT("%.2f"), s->font.scale_down_to));
fontv.emplace("max_stretch", String::Format(wxT("%.2f"), s->font.max_stretch));
fontv.emplace("color", format_color( s->font.color()));
fontv.emplace("shadow_color", format_color( s->font.shadow_color()));
fontv.emplace("shadow_displacement_x", String::Format(wxT("%.2f"), s->font.shadow_displacement_x()));
fontv.emplace("shadow_displacement_y", String::Format(wxT("%.2f"), s->font.shadow_displacement_y()));
fontv.emplace("shadow_blur", String::Format(wxT("%.2f"), s->font.shadow_blur()));
fontv.emplace("stroke_color", format_color( s->font.stroke_color()));
fontv.emplace("stroke_radius", String::Format(wxT("%.2f"), s->font.stroke_radius()));
fontv.emplace("stroke_blur", String::Format(wxT("%.2f"), s->font.stroke_blur()));
fontv.emplace("separator_color", format_color( s->font.separator_color));
fontv.emplace("flags", String::Format(wxT("%i"), s->font.flags));
stylev.emplace("font", fontv);
fontv.emplace("name", s->font.name());
fontv.emplace("italic_name", s->font.italic_name());
fontv.emplace("size", wxString::Format(wxT("%.2f"), s->font.size()));
fontv.emplace("weight", s->font.weight());
fontv.emplace("style", s->font.style());
fontv.emplace("underline", s->font.underline());
fontv.emplace("strikethrough", s->font.strikethrough());
fontv.emplace("scale_down_to", wxString::Format(wxT("%.2f"), s->font.scale_down_to));
fontv.emplace("max_stretch", wxString::Format(wxT("%.2f"), s->font.max_stretch));
fontv.emplace("color", format_color( s->font.color()));
fontv.emplace("shadow_color", format_color( s->font.shadow_color()));
fontv.emplace("shadow_displacement_x", wxString::Format(wxT("%.2f"), s->font.shadow_displacement_x()));
fontv.emplace("shadow_displacement_y", wxString::Format(wxT("%.2f"), s->font.shadow_displacement_y()));
fontv.emplace("shadow_blur", wxString::Format(wxT("%.2f"), s->font.shadow_blur()));
fontv.emplace("stroke_color", format_color( s->font.stroke_color()));
fontv.emplace("stroke_radius", wxString::Format(wxT("%.2f"), s->font.stroke_radius()));
fontv.emplace("stroke_blur", wxString::Format(wxT("%.2f"), s->font.stroke_blur()));
fontv.emplace("separator_color", format_color( s->font.separator_color));
fontv.emplace("flags", wxString::Format(wxT("%i"), s->font.flags));
stylev.emplace("font", fontv);
boost::json::object choiceimagesv;
for (auto choice_image : s->choice_images) {
@@ -682,33 +652,33 @@ boost::json::object mse_to_json(const StyleP& style) {
else if (ChoiceStyle* s = dynamic_cast<ChoiceStyle*>(style.get())) {
stylev.emplace("field_type", dynamic_cast<BooleanStyle*>(style.get()) ? "boolean" : "choice");
stylev.emplace("popup_style", popup_style_to_string( s->popup_style));
stylev.emplace("render_style", render_style_to_string( s->render_style));
stylev.emplace("image", s->image.toScriptString());
stylev.emplace("combine", combine_to_string( s->combine));
stylev.emplace("alignment", alignment_to_string( s->alignment));
stylev.emplace("popup_style", popup_style_to_string( s->popup_style));
stylev.emplace("render_style", render_style_to_string( s->render_style));
stylev.emplace("image", s->image.toScriptString());
stylev.emplace("combine", combine_to_string( s->combine));
stylev.emplace("alignment", alignment_to_string( s->alignment));
boost::json::object fontv;
fontv.emplace("name", s->font.name());
fontv.emplace("italic_name", s->font.italic_name());
fontv.emplace("size", String::Format(wxT("%.2f"), s->font.size()));
fontv.emplace("weight", s->font.weight());
fontv.emplace("style", s->font.style());
fontv.emplace("underline", s->font.underline());
fontv.emplace("strikethrough", s->font.strikethrough());
fontv.emplace("scale_down_to", String::Format(wxT("%.2f"), s->font.scale_down_to));
fontv.emplace("max_stretch", String::Format(wxT("%.2f"), s->font.max_stretch));
fontv.emplace("color", format_color( s->font.color()));
fontv.emplace("shadow_color", format_color( s->font.shadow_color()));
fontv.emplace("shadow_displacement_x", String::Format(wxT("%.2f"), s->font.shadow_displacement_x()));
fontv.emplace("shadow_displacement_y", String::Format(wxT("%.2f"), s->font.shadow_displacement_y()));
fontv.emplace("shadow_blur", String::Format(wxT("%.2f"), s->font.shadow_blur()));
fontv.emplace("stroke_color", format_color( s->font.stroke_color()));
fontv.emplace("stroke_radius", String::Format(wxT("%.2f"), s->font.stroke_radius()));
fontv.emplace("stroke_blur", String::Format(wxT("%.2f"), s->font.stroke_blur()));
fontv.emplace("separator_color", format_color( s->font.separator_color));
fontv.emplace("flags", String::Format(wxT("%i"), s->font.flags));
stylev.emplace("font", fontv);
fontv.emplace("name", s->font.name());
fontv.emplace("italic_name", s->font.italic_name());
fontv.emplace("size", wxString::Format(wxT("%.2f"), s->font.size()));
fontv.emplace("weight", s->font.weight());
fontv.emplace("style", s->font.style());
fontv.emplace("underline", s->font.underline());
fontv.emplace("strikethrough", s->font.strikethrough());
fontv.emplace("scale_down_to", wxString::Format(wxT("%.2f"), s->font.scale_down_to));
fontv.emplace("max_stretch", wxString::Format(wxT("%.2f"), s->font.max_stretch));
fontv.emplace("color", format_color( s->font.color()));
fontv.emplace("shadow_color", format_color( s->font.shadow_color()));
fontv.emplace("shadow_displacement_x", wxString::Format(wxT("%.2f"), s->font.shadow_displacement_x()));
fontv.emplace("shadow_displacement_y", wxString::Format(wxT("%.2f"), s->font.shadow_displacement_y()));
fontv.emplace("shadow_blur", wxString::Format(wxT("%.2f"), s->font.shadow_blur()));
fontv.emplace("stroke_color", format_color( s->font.stroke_color()));
fontv.emplace("stroke_radius", wxString::Format(wxT("%.2f"), s->font.stroke_radius()));
fontv.emplace("stroke_blur", wxString::Format(wxT("%.2f"), s->font.stroke_blur()));
fontv.emplace("separator_color", format_color( s->font.separator_color));
fontv.emplace("flags", wxString::Format(wxT("%i"), s->font.flags));
stylev.emplace("font", fontv);
boost::json::object choiceimagesv;
for (auto choice_image : s->choice_images) {
@@ -722,71 +692,71 @@ boost::json::object mse_to_json(const StyleP& style) {
stylev.emplace("field_type", "package_choice");
boost::json::object fontv;
fontv.emplace("name", s->font.name());
fontv.emplace("italic_name", s->font.italic_name());
fontv.emplace("size", String::Format(wxT("%.2f"), s->font.size()));
fontv.emplace("weight", s->font.weight());
fontv.emplace("style", s->font.style());
fontv.emplace("underline", s->font.underline());
fontv.emplace("strikethrough", s->font.strikethrough());
fontv.emplace("scale_down_to", String::Format(wxT("%.2f"), s->font.scale_down_to));
fontv.emplace("max_stretch", String::Format(wxT("%.2f"), s->font.max_stretch));
fontv.emplace("color", format_color( s->font.color()));
fontv.emplace("shadow_color", format_color( s->font.shadow_color()));
fontv.emplace("shadow_displacement_x", String::Format(wxT("%.2f"), s->font.shadow_displacement_x()));
fontv.emplace("shadow_displacement_y", String::Format(wxT("%.2f"), s->font.shadow_displacement_y()));
fontv.emplace("shadow_blur", String::Format(wxT("%.2f"), s->font.shadow_blur()));
fontv.emplace("stroke_color", format_color( s->font.stroke_color()));
fontv.emplace("stroke_radius", String::Format(wxT("%.2f"), s->font.stroke_radius()));
fontv.emplace("stroke_blur", String::Format(wxT("%.2f"), s->font.stroke_blur()));
fontv.emplace("separator_color", format_color( s->font.separator_color));
fontv.emplace("flags", String::Format(wxT("%i"), s->font.flags));
stylev.emplace("font", fontv);
fontv.emplace("name", s->font.name());
fontv.emplace("italic_name", s->font.italic_name());
fontv.emplace("size", wxString::Format(wxT("%.2f"), s->font.size()));
fontv.emplace("weight", s->font.weight());
fontv.emplace("style", s->font.style());
fontv.emplace("underline", s->font.underline());
fontv.emplace("strikethrough", s->font.strikethrough());
fontv.emplace("scale_down_to", wxString::Format(wxT("%.2f"), s->font.scale_down_to));
fontv.emplace("max_stretch", wxString::Format(wxT("%.2f"), s->font.max_stretch));
fontv.emplace("color", format_color( s->font.color()));
fontv.emplace("shadow_color", format_color( s->font.shadow_color()));
fontv.emplace("shadow_displacement_x", wxString::Format(wxT("%.2f"), s->font.shadow_displacement_x()));
fontv.emplace("shadow_displacement_y", wxString::Format(wxT("%.2f"), s->font.shadow_displacement_y()));
fontv.emplace("shadow_blur", wxString::Format(wxT("%.2f"), s->font.shadow_blur()));
fontv.emplace("stroke_color", format_color( s->font.stroke_color()));
fontv.emplace("stroke_radius", wxString::Format(wxT("%.2f"), s->font.stroke_radius()));
fontv.emplace("stroke_blur", wxString::Format(wxT("%.2f"), s->font.stroke_blur()));
fontv.emplace("separator_color", format_color( s->font.separator_color));
fontv.emplace("flags", wxString::Format(wxT("%i"), s->font.flags));
stylev.emplace("font", fontv);
}
else if (ColorStyle* s = dynamic_cast<ColorStyle*>(style.get())) {
stylev.emplace("field_type", "color");
stylev.emplace("radius", String::Format(wxT("%.2f"), s->radius()));
stylev.emplace("left_width", String::Format(wxT("%.2f"), s->left_width()));
stylev.emplace("right_width", String::Format(wxT("%.2f"), s->right_width()));
stylev.emplace("top_width", String::Format(wxT("%.2f"), s->top_width()));
stylev.emplace("bottom_width", String::Format(wxT("%.2f"), s->bottom_width()));
stylev.emplace("combine", combine_to_string( s->combine));
stylev.emplace("radius", wxString::Format(wxT("%.2f"), s->radius()));
stylev.emplace("left_width", wxString::Format(wxT("%.2f"), s->left_width()));
stylev.emplace("right_width", wxString::Format(wxT("%.2f"), s->right_width()));
stylev.emplace("top_width", wxString::Format(wxT("%.2f"), s->top_width()));
stylev.emplace("bottom_width", wxString::Format(wxT("%.2f"), s->bottom_width()));
stylev.emplace("combine", combine_to_string( s->combine));
}
else if (SymbolStyle* s = dynamic_cast<SymbolStyle*>(style.get())) {
stylev.emplace("field_type", "symbol");
stylev.emplace("min_aspect_ratio", String::Format(wxT("%.2f"), s->min_aspect_ratio));
stylev.emplace("max_aspect_ratio", String::Format(wxT("%.2f"), s->max_aspect_ratio));
stylev.emplace("min_aspect_ratio", wxString::Format(wxT("%.2f"), s->min_aspect_ratio));
stylev.emplace("max_aspect_ratio", wxString::Format(wxT("%.2f"), s->max_aspect_ratio));
boost::json::array variationsv;
int size = s->variations.size();
for (int i = 0; i < size; i++) {
boost::json::object variationv;
variationv.emplace("name", s->variations[i]->name);
variationv.emplace("border_radius", String::Format(wxT("%.2f"), s->variations[i]->border_radius));
variationv.emplace("name", s->variations[i]->name);
variationv.emplace("border_radius", wxString::Format(wxT("%.2f"), s->variations[i]->border_radius));
SymbolFilterP filter = s->variations[i]->filter;
if (SolidFillSymbolFilter* f = dynamic_cast<SolidFillSymbolFilter*>(filter.get())) {
variationv.emplace("fill_type", f->fillType());
variationv.emplace("fill_color", format_color( f->fill_color));
variationv.emplace("border_color", format_color( f->border_color));
variationv.emplace("fill_type", f->fillType());
variationv.emplace("fill_color", format_color( f->fill_color));
variationv.emplace("border_color", format_color( f->border_color));
}
else if (RadialGradientSymbolFilter* f = dynamic_cast<RadialGradientSymbolFilter*>(filter.get())) {
variationv.emplace("fill_type", f->fillType());
variationv.emplace("fill_color_1", format_color( f->fill_color_1));
variationv.emplace("fill_color_2", format_color( f->fill_color_2));
variationv.emplace("border_color_1", format_color( f->border_color_1));
variationv.emplace("border_color_2", format_color( f->border_color_2));
variationv.emplace("fill_type", f->fillType());
variationv.emplace("fill_color_1", format_color( f->fill_color_1));
variationv.emplace("fill_color_2", format_color( f->fill_color_2));
variationv.emplace("border_color_1", format_color( f->border_color_1));
variationv.emplace("border_color_2", format_color( f->border_color_2));
}
else if (LinearGradientSymbolFilter* f = dynamic_cast<LinearGradientSymbolFilter*>(filter.get())) {
variationv.emplace("fill_type", f->fillType());
variationv.emplace("fill_color_1", format_color( f->fill_color_1));
variationv.emplace("fill_color_2", format_color( f->fill_color_2));
variationv.emplace("border_color_1", format_color( f->border_color_1));
variationv.emplace("border_color_2", format_color( f->border_color_2));
variationv.emplace("center_x", String::Format(wxT("%.2f"), f->center_x));
variationv.emplace("center_y", String::Format(wxT("%.2f"), f->center_y));
variationv.emplace("end_x", String::Format(wxT("%.2f"), f->end_x));
variationv.emplace("end_y", String::Format(wxT("%.2f"), f->end_y));
variationv.emplace("fill_type", f->fillType());
variationv.emplace("fill_color_1", format_color( f->fill_color_1));
variationv.emplace("fill_color_2", format_color( f->fill_color_2));
variationv.emplace("border_color_1", format_color( f->border_color_1));
variationv.emplace("border_color_2", format_color( f->border_color_2));
variationv.emplace("center_x", wxString::Format(wxT("%.2f"), f->center_x));
variationv.emplace("center_y", wxString::Format(wxT("%.2f"), f->center_y));
variationv.emplace("end_x", wxString::Format(wxT("%.2f"), f->end_x));
variationv.emplace("end_y", wxString::Format(wxT("%.2f"), f->end_y));
}
variationsv.emplace_back(variationv);
}
@@ -795,34 +765,34 @@ boost::json::object mse_to_json(const StyleP& style) {
else if (InfoStyle* s = dynamic_cast<InfoStyle*>(style.get())) {
stylev.emplace("field_type", "info");
stylev.emplace("alignment", alignment_to_string( s->alignment));
stylev.emplace("padding_left", String::Format(wxT("%.2f"), s->padding_left));
stylev.emplace("padding_right", String::Format(wxT("%.2f"), s->padding_right));
stylev.emplace("padding_top", String::Format(wxT("%.2f"), s->padding_top));
stylev.emplace("padding_bottom", String::Format(wxT("%.2f"), s->padding_bottom));
stylev.emplace("background_color", format_color( s->background_color));
stylev.emplace("alignment", alignment_to_string( s->alignment));
stylev.emplace("padding_left", wxString::Format(wxT("%.2f"), s->padding_left));
stylev.emplace("padding_right", wxString::Format(wxT("%.2f"), s->padding_right));
stylev.emplace("padding_top", wxString::Format(wxT("%.2f"), s->padding_top));
stylev.emplace("padding_bottom", wxString::Format(wxT("%.2f"), s->padding_bottom));
stylev.emplace("background_color", format_color( s->background_color));
boost::json::object fontv;
fontv.emplace("name", s->font.name());
fontv.emplace("italic_name", s->font.italic_name());
fontv.emplace("size", String::Format(wxT("%.2f"), s->font.size()));
fontv.emplace("weight", s->font.weight());
fontv.emplace("style", s->font.style());
fontv.emplace("underline", s->font.underline());
fontv.emplace("strikethrough", s->font.strikethrough());
fontv.emplace("scale_down_to", String::Format(wxT("%.2f"), s->font.scale_down_to));
fontv.emplace("max_stretch", String::Format(wxT("%.2f"), s->font.max_stretch));
fontv.emplace("color", format_color( s->font.color()));
fontv.emplace("shadow_color", format_color( s->font.shadow_color()));
fontv.emplace("shadow_displacement_x", String::Format(wxT("%.2f"), s->font.shadow_displacement_x()));
fontv.emplace("shadow_displacement_y", String::Format(wxT("%.2f"), s->font.shadow_displacement_y()));
fontv.emplace("shadow_blur", String::Format(wxT("%.2f"), s->font.shadow_blur()));
fontv.emplace("stroke_color", format_color( s->font.stroke_color()));
fontv.emplace("stroke_radius", String::Format(wxT("%.2f"), s->font.stroke_radius()));
fontv.emplace("stroke_blur", String::Format(wxT("%.2f"), s->font.stroke_blur()));
fontv.emplace("separator_color", format_color( s->font.separator_color));
fontv.emplace("flags", String::Format(wxT("%i"), s->font.flags));
stylev.emplace("font", fontv);
fontv.emplace("name", s->font.name());
fontv.emplace("italic_name", s->font.italic_name());
fontv.emplace("size", wxString::Format(wxT("%.2f"), s->font.size()));
fontv.emplace("weight", s->font.weight());
fontv.emplace("style", s->font.style());
fontv.emplace("underline", s->font.underline());
fontv.emplace("strikethrough", s->font.strikethrough());
fontv.emplace("scale_down_to", wxString::Format(wxT("%.2f"), s->font.scale_down_to));
fontv.emplace("max_stretch", wxString::Format(wxT("%.2f"), s->font.max_stretch));
fontv.emplace("color", format_color( s->font.color()));
fontv.emplace("shadow_color", format_color( s->font.shadow_color()));
fontv.emplace("shadow_displacement_x", wxString::Format(wxT("%.2f"), s->font.shadow_displacement_x()));
fontv.emplace("shadow_displacement_y", wxString::Format(wxT("%.2f"), s->font.shadow_displacement_y()));
fontv.emplace("shadow_blur", wxString::Format(wxT("%.2f"), s->font.shadow_blur()));
fontv.emplace("stroke_color", format_color( s->font.stroke_color()));
fontv.emplace("stroke_radius", wxString::Format(wxT("%.2f"), s->font.stroke_radius()));
fontv.emplace("stroke_blur", wxString::Format(wxT("%.2f"), s->font.stroke_blur()));
fontv.emplace("separator_color", format_color( s->font.separator_color));
fontv.emplace("flags", wxString::Format(wxT("%i"), s->font.flags));
stylev.emplace("font", fontv);
}
return stylev;
@@ -872,7 +842,7 @@ boost::json::object mse_to_json(const IndexMap<FieldP, ValueP>& map) {
return indexmapv;
}
boost::json::value mse_to_json(const ScriptValueP& sv, Set* set, bool suppress_warnings) {
boost::json::value mse_to_json(const ScriptValueP& sv, Set* set) {
// special types
if (ScriptObject<PackItemP>* o = dynamic_cast<ScriptObject<PackItemP>*> (sv.get())) return mse_to_json( o->getValue());
if (ScriptObject<PackTypeP>* o = dynamic_cast<ScriptObject<PackTypeP>*> (sv.get())) return mse_to_json( o->getValue());
@@ -936,6 +906,6 @@ boost::json::value mse_to_json(const ScriptValueP& sv, Set* set, bool suppress_w
}
}
}
if (!suppress_warnings) queue_message(MESSAGE_WARNING, _ERROR_1_("json unknown script type", sv->typeName()));
queue_message(MESSAGE_ERROR, _ERROR_1_("json unknown script type", sv->typeName()));
return boost::json::value(nullptr);
}
+1 -1
View File
@@ -72,4 +72,4 @@ boost::json::object mse_to_json(const Set* set);
boost::json::object mse_to_json(const IndexMap<FieldP,ValueP>& map);
boost::json::value mse_to_json(const ScriptValueP& sv, Set* set, bool suppress_warnings = false);
boost::json::value mse_to_json(const ScriptValueP& sv, Set* set);
-15
View File
@@ -32,21 +32,6 @@ IndexMap<Key,Value>& DelayedIndexMaps<Key,Value>::get(const String& name, const
return item->read_data;
}
/// Initialize this map with cloned values from another map
template <typename Key, typename Value>
void DelayedIndexMaps<Key,Value>::cloneFrom(const DelayedIndexMaps<Key,Value>& values) {
clear();
for (const auto& [name, src_ptr] : values.data) {
if (!src_ptr) continue;
auto dst_ptr = make_intrusive<DelayedIndexMapsData<Key,Value>>();
dst_ptr->unread_data = src_ptr->unread_data;
if (src_ptr->unread_data.empty()) {
dst_ptr->read_data.cloneFrom(src_ptr->read_data);
}
data[name] = dst_ptr;
}
}
template <typename Key, typename Value>
void DelayedIndexMaps<Key,Value>::clear() {
data.clear();
+2 -4
View File
@@ -60,8 +60,8 @@ public:
}
return true;
}
/// Initialize this map with cloned values from another map
void cloneFrom(const IndexMap<Key,Value>& values) {
/// Initialize this map with cloned values from another list
void cloneFrom(const IndexMap<Key,Value>& values) {
if (this->size() == values.size()) return;
this->reserve(values.size());
for(size_t index = size() ; index < values.size() ; ++index) {
@@ -147,8 +147,6 @@ class DelayedIndexMaps {
public:
/// Get the data for a specific name. Initialize the map with init_with (if it is not alread initialized)
IndexMap<Key,Value>& get(const String& name, const vector<Key>& init_with);
/// Initialize this map with cloned values from another map
void cloneFrom(const DelayedIndexMaps<Key,Value>& values);
/// Clear the delayed index map
void clear();
map<String, intrusive_ptr<DelayedIndexMapsData<Key,Value>>> data;
+2 -2
View File
@@ -684,9 +684,7 @@ void Packaged::validate(Version) {
void Packaged::requireDependency(Packaged* package) {
if (package == this) return; // dependency on self
if (this->relativeFilename().find("mse-set") != String::npos) return; // skip checks on sets
String n = package->relativeFilename();
if (n.find("mse-symbol-font") != String::npos) return; // skip checks for symbol-fonts
FOR_EACH(dep, dependencies) {
if (dep->package == n) {
if (package->version < dep->version) {
@@ -698,6 +696,8 @@ void Packaged::requireDependency(Packaged* package) {
}
}
}
// skip dependency checks for symbol-fonts
if (package->relativeFilename().find("mse-symbol-font") != std::string::npos) return;
// dependency not found
queue_message(MESSAGE_WARNING,_ERROR_4_("dependency not given", name(), package->relativeFilename(), package->relativeFilename(), package->version.toString()));
}
+4 -4
View File
@@ -18,9 +18,9 @@ using boost::tribool;
// ----------------------------------------------------------------------------- : Reader
Reader::Reader(wxInputStream& input, Packaged* package, const String& filename, bool ignore_invalid, bool suppress_warnings)
Reader::Reader(wxInputStream& input, Packaged* package, const String& filename, bool ignore_invalid)
: indent(0), expected_indent(0), state(OUTSIDE)
, ignore_invalid(ignore_invalid), suppress_warnings(suppress_warnings)
, ignore_invalid(ignore_invalid)
, filename(filename), package(package), line_number(0), previous_line_number(0)
, input(input)
{
@@ -30,7 +30,7 @@ Reader::Reader(wxInputStream& input, Packaged* package, const String& filename,
handleAppVersion();
}
void Reader::handleIgnore(Version end_version, const Char* a) {
void Reader::handleIgnore(int end_version, const Char* a) {
if (file_app_version < end_version) {
if (enterBlock(a)) exitBlock();
}
@@ -53,7 +53,7 @@ void Reader::warning(const String& msg, int line_number_delta, bool warn_on_prev
}
void Reader::showWarnings() {
if (!suppress_warnings && !warnings.empty()) {
if (!warnings.empty()) {
queue_message(MESSAGE_WARNING, _("Warnings while reading file:\n") + filename + _("\n") + warnings);
warnings.clear();
}
+4 -6
View File
@@ -38,7 +38,7 @@ public:
/** filename is used only for error messages
* package is used for looking up included files.
*/
Reader(wxInputStream& input, Packaged* package = nullptr, const String& filename = _(""), bool ignore_invalid = false, bool suppress_warnings = false);
Reader(wxInputStream& input, Packaged* package = nullptr, const String& filename = _(""), bool ignore_invalid = false);
~Reader() { showWarnings(); }
@@ -49,7 +49,7 @@ public:
/// Is the thing currently being read 'complex', i.e. does it have children
inline bool isCompound() const { return indent != expected_indent - 1 || value.empty(); }
/// Ignore old keys
void handleIgnore(Version, const Char*);
void handleIgnore(int, const Char*);
/// Get the version of the format we are reading
inline Version formatVersion() const { return file_app_version; }
@@ -148,9 +148,7 @@ private:
} state;
/// Should all invalid keys be ignored?
bool ignore_invalid;
/// Should warnings be emitted?
bool suppress_warnings;
/// Filename for error messages
String filename;
/// Package this file is from, if any
@@ -189,7 +187,7 @@ private:
value = key == _("include_localized_file") ? addLocale(value) : key == _("include_dark_file") ? addDark(value) : value;
auto [stream, include_package] = openFileFromPackage(package, value);
Reader sub_reader(*stream, include_package, value, ignore_invalid);
if (sub_reader.file_app_version.isZero()) {
if (sub_reader.file_app_version == 0) {
// in an included file, use the app version of the parent if there is none
sub_reader.file_app_version = file_app_version;
}
+1 -29
View File
@@ -9,8 +9,7 @@
#include <util/prec.hpp>
#include <util/rotation.hpp>
#include <gfx/gfx.hpp>
#include <data/font.hpp>
#include <wx/rawbmp.h>
#include <data/font.hpp>
// ----------------------------------------------------------------------------- : Rotation
@@ -277,33 +276,6 @@ 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);
wxMemoryDC memDC(bmp);
memDC.Blit(0, 0, r_ext.width, r_ext.height, &dc, r_ext.x, r_ext.y);
memDC.SelectObject(wxNullBitmap);
wxNativePixelData data(bmp);
if (!data) return; // Raw access not available on this platform/bitmap
wxNativePixelData::Iterator p(data);
for (int j = 0; j < r_ext.height; ++j) {
wxNativePixelData::Iterator rowStart = p;
for (int i = 0; i < r_ext.width; ++i) {
// Invert each channel
p.Red() = 255 - p.Red();
p.Green() = 255 - p.Green();
p.Blue() = 255 - p.Blue();
++p; // Move to next pixel in the row
}
p = rowStart;
p.OffsetY(data, 1); // Move to the next row
}
dc.DrawBitmap(bmp, RealPoint(r_ext.x, r_ext.y));
}
void RotatedDC::DrawCircle(const RealPoint& center, double radius) {
wxPoint p = tr(center);
dc.DrawCircle(p.x + 1, p.y + 1, int(trS(radius)));
-1
View File
@@ -173,7 +173,6 @@ public:
void DrawLine (const RealPoint& p1, const RealPoint& p2);
void DrawRectangle(const RealRect& r);
void DrawRoundedRectangle(const RealRect& r, double radius);
void DrawInvertRectangle(const RealRect& r);
void DrawCircle(const RealPoint& center, double radius);
void DrawEllipse(const RealPoint& center, const RealSize& size);
/// Draw an arc of an ellipse, angles are in radians
+25 -27
View File
@@ -13,32 +13,30 @@
// ----------------------------------------------------------------------------- : Version
UInt Version::toNumber() const { return major * 10000 + minor * 100 + revision; }
UInt Version::toNumber() const { return version; }
String Version::toString() const {
if (major >= 2000) {
// the version is a date, use ISO notation
if (version > 20000000) {
// major > 2000, the version is a date, use ISO notation
return String::Format(_("%04d-%02d-%02d"),
major,
minor,
revision);
(version / 10000) ,
(version / 100) % 100,
(version / 1) % 100);
} else {
return String::Format(_("%d.%d.%d"),
major,
minor,
revision);
(version / 10000) ,
(version / 100) % 100,
(version / 1) % 100);
}
}
Version Version::fromString(const String& version) {
if (version.empty()) return Version();
UInt major = 0, minor = 0, revision = 0;
if (wxSscanf(version, _("%u.%u.%u"), &major, &minor, &revision)<=1) // a.b.c style
wxSscanf(version, _("%u-%u-%u"), &major, &minor, &revision); // date style
return Version(major, minor, revision);
Version Version::fromString(const String& version) {
UInt major = 0, minor = 0, build = 0;
if (wxSscanf(version, _("%u.%u.%u"), &major, &minor, &build)<=1) // a.b.c style
wxSscanf(version, _("%u-%u-%u"), &major, &minor, &build); // date style
return Version(major * 10000 + minor * 100 + build);
}
bool Version::isZero() const { return revision == 0u && minor == 0u && major == 0u; }
template <> void Reader::handle(Version& v) {
v = Version::fromString(getValue());
@@ -53,7 +51,7 @@ template <> void GetDefaultMember::handle(const Version& v) {
// ----------------------------------------------------------------------------- : Versions
// NOTE: Don't use leading zeroes, they mean octal
const Version app_version = Version(MSE_VERSION_MAJOR, MSE_VERSION_MINOR, MSE_VERSION_PATCH);
const Version app_version = 10000 * MSE_VERSION_MAJOR + 100 * MSE_VERSION_MINOR + MSE_VERSION_PATCH;
#if defined UNOFFICIAL_BUILD
const Char* version_suffix = _(" (Unofficial)");
@@ -90,13 +88,13 @@ const Char* version_suffix = _(" (ascii build)");
* 2.0.0 : bugfix release mostly, added error console
* 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_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_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_locale = 20002; // 2.0.2
const Version file_version_set = 20002; // 2.0.2
const Version file_version_game = 308; // 0.3.8
const Version file_version_stylesheet = 308; // 0.3.8
const Version file_version_symbol_font = 306; // 0.3.6
const Version file_version_export_template = 307; // 0.3.7
const Version file_version_installer = 307; // 0.3.7
const Version file_version_symbol = 305; // 0.3.5
const Version file_version_clipboard = 20002; // 2.0.2
const Version file_version_script = 307; // 0.3.7
+13 -36
View File
@@ -21,34 +21,16 @@
/// A version number
struct Version {
public:
Version() : major(0u), minor(0u), revision(0u) {}
Version(UInt major, UInt minor, UInt revision) : major(major), minor(minor), revision(revision) {}
bool operator==(const Version& v) const {
return std::tie(major, minor, revision)
== std::tie(v.major, v.minor, v.revision);
}
bool operator!=(const Version& v) const {
return std::tie(major, minor, revision)
!= std::tie(v.major, v.minor, v.revision);
}
bool operator<(const Version& v) const {
return std::tie(major, minor, revision)
< std::tie(v.major, v.minor, v.revision);
}
bool operator>(const Version& v) const {
return std::tie(major, minor, revision)
> std::tie(v.major, v.minor, v.revision);
}
bool operator<=(const Version& v) const {
return std::tie(major, minor, revision)
<= std::tie(v.major, v.minor, v.revision);
}
bool operator>=(const Version& v) const {
return std::tie(major, minor, revision)
>= std::tie(v.major, v.minor, v.revision);
}
Version() : version(0) {}
Version(UInt version) : version(version) {}
inline bool operator == (Version v) const { return version == v.version; }
inline bool operator != (Version v) const { return version != v.version; }
inline bool operator < (Version v) const { return version < v.version; }
inline bool operator <= (Version v) const { return version <= v.version; }
inline bool operator > (Version v) const { return version > v.version; }
inline bool operator >= (Version v) const { return version >= v.version; }
/// Convert a version number to a string
String toString() const;
/// Get the version number as an integer number
@@ -56,14 +38,9 @@ public:
/// Convert a string to a version number
static Version fromString(const String& version);
/// Did this version get properly initialized?
bool isZero() const;
private:
UInt major = 0;
UInt minor = 0;
UInt revision = 0;
private:
UInt version; ///< Version number encoded as aabbcc, where a=major, b=minor, c=revision
};
// ----------------------------------------------------------------------------- : Versions

Some files were not shown because too many files have changed in this diff Show More