35 Commits

Author SHA1 Message Date
GenevensiS d9b58bb5eb Selection highlight debug for linux
this is not optimized but it'll do for now
2026-06-05 05:08:57 +02:00
GenevensiS 512a237f39 fix keywords panel 2026-06-05 02:45:56 +02:00
GenevensiS 1a64496206 fix bug not loading links correctly 2026-05-27 20:30:38 +02:00
GenevensiS 23463c4b96 don't print scientific notation in to_json 2026-05-24 16:14:13 +02:00
GenevensiS 6f526a81f1 fix link window appearing on wrong monitor 2026-05-24 13:25:26 +02:00
GenevensiS ae02c71be6 console and to_json function now accept stylesheets, games and style index maps 2026-05-20 15:50:54 +02:00
GenevensiS c531b8aa74 Add option to download missing stylesheets on startup 2026-05-18 23:31:39 +02:00
GenevensiS 2f77e8c4c1 fix compile 2026-05-15 18:23:27 +02:00
GenevensiS 754ca3bccf add "update group" buttons to package manager 2026-05-15 15:37:56 +02:00
GenevensiS 8fadb1f099 fix compile 2026-05-14 19:24:35 +02:00
GenevensiS a335b730ca apply update scripts in correct order 2026-05-14 19:00:50 +02:00
GenevensiS 76af996f0a tweaks
allow import_image to accept script images
import_image and download_image no longer save the set or require it to have been saved once
console panel now tries to output toJson() before falling back to toCode()
2026-05-14 13:50:02 +02:00
GenevensiS 6f4fc0066d update locales 2026-05-13 18:11:08 +02:00
GenevensiS 151a04909a Add update_cards_scripts 2026-05-13 18:09:56 +02:00
GenevensiS f4fe9ab6b0 Strengthen paste logic 2026-05-11 13:51:43 +02:00
GenevensiS 2135a14b17 FINE I'll do it myself 2026-05-11 13:11:37 +02:00
GenevensiS 72830ec218 Update viewer.cpp 2026-05-11 11:57:16 +02:00
GenevensiS b13de8e099 add "version_is_older" script function 2026-05-11 10:29:29 +02:00
GenevensiS 24abf8fe86 add "exists_as_package" script function 2026-05-11 09:32:13 +02:00
GenevensiS 19b144f37b restore ability to paste in Paint 2026-05-10 09:39:19 +02:00
GenevensiS 50b649beca add "add double faced card" menu option 2026-05-09 19:42:19 +02:00
GenevensiS d79e8afb56 add new_uid script function 2026-05-09 18:10:59 +02:00
GenevensiS d4efc5b973 improve blending error messages 2026-05-07 11:34:15 +02:00
GenevensiS 9b51ca0537 tweak text highlight logic 2026-05-05 08:51:27 +02:00
GenevensiS 8a86778bfb refactor card copy pasting 2026-05-04 12:15:13 +02:00
GenevensiS 3c2c3ac977 fake stable sort on card list 2026-05-04 07:01:52 +02:00
GenevensiS db1fd4f343 fix copy pasting bugs 2026-05-04 05:27:11 +02:00
GenevensiS 8cc17abecc add card uid map 2026-05-04 02:21:33 +02:00
GenevensiS 9a5be16e4e fix bug with image decoding 2026-05-03 05:03:08 +02:00
GenevensiS 05d205cafa update locales 2026-04-26 21:13:02 +02:00
GenevensiS 8c0e5f3e71 add info to package manager window 2026-04-26 21:01:42 +02:00
GenevensiS 72724a35c7 allow set_alpha to handle values > 1.0 2026-04-24 15:27:21 +02:00
GenevensiS 0baa73ae7d fix bugs
- dimensions_of should now work in all contexts
- import_image now works in style files, although should be avoided, since it reloads the file every time the code in run, it should be used in one shot scripts, like import scripts and bulk modification scripts
- process_english_hints now correctly processes <singular> and <plural> tags
2026-04-24 13:18:40 +02:00
GenevensiS d782e4851c add is_default script function 2026-04-19 19:06:52 +02:00
GenevensiS 17dd3cf407 add exceptions to english_plural and english_singular 2026-04-19 16:04:20 +02:00
134 changed files with 3775 additions and 1201 deletions
+3 -4
View File
@@ -27,10 +27,9 @@ if( NOT HUNSPELL_FOUND )
endif() endif()
endif() endif()
# You will most likely get a message about being unable to open hunspell-1.7.lib because pkgconf forgets to add the actual path to # You will most likely get a message about being unable to open hunspell-1.7.lib because pkgconf forgets to add the actual path to HUNSPELL_LIBRARIES.
# HUNSPELL_LIBRARIES. If so, uncomment the below line and point it to the correct vcpkg root folder/library. # If so, uncomment the below line and point it to the correct vcpkg root folder/library. (For debug builds, add "debug\\" just before "lib\\")
#set(HUNSPELL_LIBRARIES "C:\\PATH\\TO\\ROOT\\vcpkg\\installed\\${VCPKG_TARGET_TRIPLET}\\lib\\hunspell-1.7.lib") #set(HUNSPELL_LIBRARIES "C:\\PATH\\TO\\ROOT\\vcpkg\\installed\\${VCPKG_TARGET_TRIPLET}\\lib\\hunspell-1.7.lib")
message("-- Does this have a full path? If not, and it's just a file name, it's broken: Found Hunspell at ${HUNSPELL_LIBRARIES}")
include_directories("${PROJECT_BINARY_DIR}/src") include_directories("${PROJECT_BINARY_DIR}/src")
include_directories("${PROJECT_SOURCE_DIR}/src") include_directories("${PROJECT_SOURCE_DIR}/src")
@@ -143,4 +142,4 @@ endif()
include(test/tests.cmake) include(test/tests.cmake)
# Debug Message # Debug Message
message("-- Does this have a full path? If not, and it's just a file name, it's broken: Found Hunspell at ${HUNSPELL_LIBRARIES}") message("-- Does this have a full path? If not, and it's just a file name, it's broken: ${HUNSPELL_LIBRARIES}")
+18
View File
@@ -18,6 +18,24 @@
} }
] ]
}, },
{
"name": "x64-Debug-static",
"generator": "Ninja",
"configurationType": "Debug",
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "-DVCPKG_TARGET_TRIPLET=x64-windows-static",
"buildCommandArgs": "-v",
"ctestCommandArgs": "",
"inheritEnvironments": [ "msvc_x64_x64" ],
"variables": [
{
"name": "VCPKG_MANIFEST_FEATURES",
"value": "fonts",
"type": "STRING"
}
]
},
{ {
"name": "x86-Debug", "name": "x86-Debug",
"generator": "Ninja", "generator": "Ninja",
+36 -2
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8 mse version: 2.6.0
installer group: Magic Set Editor/translations/chinese simplified installer group: Magic Set Editor/translations/chinese simplified
full name: 简体中文 (Simplified Chinese) full name: 简体中文 (Simplified Chinese)
version: 2026-02-28 version: 2026-02-28
@@ -54,6 +54,8 @@ menu:
next card: 选择下一张卡牌 PgDn next card: 选择下一张卡牌 PgDn
search cards: 搜索卡 Ctrl+K search cards: 搜索卡 Ctrl+K
add card: 添加卡牌 Ctrl+Enter add card: 添加卡牌 Ctrl+Enter
#TODO: Localize
add card double: &Add Double Faced Card Ctrl+Shift+Enter
add cards: 批量添加卡牌... add cards: 批量添加卡牌...
remove card: 删除所选卡牌 remove card: 删除所选卡牌
#TODO: Localize #TODO: Localize
@@ -208,6 +210,8 @@ help:
next card: 选择列表中的下一张卡牌 next card: 选择列表中的下一张卡牌
search cards: 使用搜索词过滤卡片列表 search cards: 使用搜索词过滤卡片列表
add card: 添加一个新的空白卡牌到本套牌 add card: 添加一个新的空白卡牌到本套牌
#TODO: Localize
add card double: Add a new, blank, card that has a back face to this set
add cards: 添加多张卡牌到本套牌 add cards: 添加多张卡牌到本套牌
remove card: 从本套牌中删除所选卡牌 remove card: 从本套牌中删除所选卡牌
#TODO: Localize #TODO: Localize
@@ -468,6 +472,8 @@ tooltip:
# cards toolbar # cards toolbar
add card: 添加卡牌 add card: 添加卡牌
#TODO: Localize
add card double: Add double faced card
remove card: 移除选中卡牌 remove card: 移除选中卡牌
#TODO: Localize #TODO: Localize
link card: Link cards to selected card link card: Link cards to selected card
@@ -614,6 +620,16 @@ label:
stylesheet not found: stylesheet not found:
你要打开的套牌使用的是 "%s" 样式表 你要打开的套牌使用的是 "%s" 样式表
这个样式表在你的系统里没有找到,请选择其他方案 这个样式表在你的系统里没有找到,请选择其他方案
#TODO: Localize
searching online: Searching online...
#TODO: Localize
searching online fail: Not found online
#TODO: Localize
found online downloading: Found online! Downloading...
#TODO: Localize
found online installing: Found online! Installing...
#TODO: Localize
found online fail: Installation failed
# preferences dialog # preferences dialog
language: 语言 language: 语言
@@ -758,6 +774,8 @@ label:
installable version: 最新版本 installable version: 最新版本
installer size: 尺寸 installer size: 尺寸
installer status: 地位 installer status: 地位
#TODO: Localize
folder name: Folder name:
no version: - no version: -
#TODO: Localize #TODO: Localize
@@ -890,10 +908,16 @@ button:
upgrade package: 升级 upgrade package: 升级
reinstall package: 重新安装 reinstall package: 重新安装
remove package: 移除 remove package: 移除
#TODO: Localize
keep group: Keep Group As Is
install group: 全部安装 install group: 全部安装
upgrade group: 全部升级 upgrade group: 全部升级
remove group: 全部移除 remove group: 全部移除
# stylesheet not found dialog
#TODO: Localize
find package online: Search Online
############################################################## Titles in the GUI ############################################################## Titles in the GUI
title: title:
# window titles # window titles
@@ -981,6 +1005,8 @@ action:
# cards # cards
#TODO: Localize Section #TODO: Localize Section
reorder cards: Reorder cards reorder cards: Reorder cards
#TODO: Localize
update card: Update card
change link: Change link change link: Change link
change notes: Change notes change notes: Change notes
change id: Change ID change id: Change ID
@@ -1052,6 +1078,12 @@ error:
file not found package like: file not found package like:
没有找到文件:'%s' 在 '%s' 文件包中 没有找到文件:'%s' 在 '%s' 文件包中
如果你尝试从别的文件包中打开文件, 使用以下格式"/package/filename" 如果你尝试从别的文件包中打开文件, 使用以下格式"/package/filename"
#TODO: Localize
file not found package like init:
File not found: '%s' in package '%s'
If this folder is empty or unused, delete it.
#TODO: Localize
package name parse error: Unable to parse package name '%s'
file parse error: file parse error:
处理文件发生错误:'%s' 处理文件发生错误:'%s'
%s %s
@@ -1130,7 +1162,9 @@ error:
# image stuff # image stuff
coordinates for blending overlap: 坐标混合重叠 coordinates for blending overlap: 坐标混合重叠
#TODO: Localize #TODO: Localize
blending different sizes: Images used for blending must have the same size in function '%s' 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)
#TODO: Localize #TODO: Localize
negative image width: Image with zero or negative width created in function '%s' negative image width: Image with zero or negative width created in function '%s'
#TODO: Localize #TODO: Localize
+36 -2
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8 mse version: 2.6.0
installer group: Magic Set Editor/translations/chinese traditional installer group: Magic Set Editor/translations/chinese traditional
full name: 繁體中文 (Traditional Chinese) full name: 繁體中文 (Traditional Chinese)
version: 2026-02-28 version: 2026-02-28
@@ -54,6 +54,8 @@ menu:
next card: 選擇下一張卡牌 PgDn next card: 選擇下一張卡牌 PgDn
search cards: 搜尋卡 Ctrl+K search cards: 搜尋卡 Ctrl+K
add card: 添加卡牌 Ctrl+Enter add card: 添加卡牌 Ctrl+Enter
#TODO: Localize
add card double: &Add Double Faced Card Ctrl+Shift+Enter
add cards: 批量添加卡牌... add cards: 批量添加卡牌...
remove card: 刪除所選卡牌 remove card: 刪除所選卡牌
#TODO: Localize #TODO: Localize
@@ -208,6 +210,8 @@ help:
next card: 選擇列表中的下一張卡牌 next card: 選擇列表中的下一張卡牌
search cards: 使用搜尋字詞過濾卡片列表 search cards: 使用搜尋字詞過濾卡片列表
add card: 添加一個新的空白卡牌到本套牌 add card: 添加一個新的空白卡牌到本套牌
#TODO: Localize
add card double: Add a new, blank, card that has a back face to this set
add cards: 添加多張卡牌到本套牌 add cards: 添加多張卡牌到本套牌
remove card: 從本套牌中刪除所選卡牌 remove card: 從本套牌中刪除所選卡牌
#TODO: Localize #TODO: Localize
@@ -466,6 +470,8 @@ tooltip:
# cards toolbar # cards toolbar
add card: 添加卡牌 add card: 添加卡牌
#TODO: Localize
add card double: Add double faced card
remove card: 移除選中卡牌 remove card: 移除選中卡牌
#TODO: Localize #TODO: Localize
link card: Link cards to selected card link card: Link cards to selected card
@@ -612,6 +618,16 @@ label:
stylesheet not found: stylesheet not found:
你要打開的套牌使用的是 "%s" 樣式表 你要打開的套牌使用的是 "%s" 樣式表
這個樣式表在你的系統里沒有找到,請選擇其他方案 這個樣式表在你的系統里沒有找到,請選擇其他方案
#TODO: Localize
searching online: Searching online...
#TODO: Localize
searching online fail: Not found online
#TODO: Localize
found online downloading: Found online! Downloading...
#TODO: Localize
found online installing: Found online! Installing...
#TODO: Localize
found online fail: Installation failed
# preferences dialog # preferences dialog
language: 語言 language: 語言
@@ -756,6 +772,8 @@ label:
installable version: 最新版本 installable version: 最新版本
installer size: 尺寸 installer size: 尺寸
installer status: 地位 installer status: 地位
#TODO: Localize
folder name: Folder name:
no version: - no version: -
#TODO: Localize #TODO: Localize
@@ -888,10 +906,16 @@ button:
upgrade package: 昇級 upgrade package: 昇級
reinstall package: 重新安裝 reinstall package: 重新安裝
remove package: 移除 remove package: 移除
#TODO: Localize
keep group: Keep Group As Is
install group: 全部安裝 install group: 全部安裝
upgrade group: 全部昇級 upgrade group: 全部昇級
remove group: 全部移除 remove group: 全部移除
# stylesheet not found dialog
#TODO: Localize
find package online: Search Online
############################################################## Titles in the GUI ############################################################## Titles in the GUI
title: title:
# window titles # window titles
@@ -979,6 +1003,8 @@ action:
# cards # cards
#TODO: Localize Section #TODO: Localize Section
reorder cards: Reorder cards reorder cards: Reorder cards
#TODO: Localize
update card: Update card
change link: Change link change link: Change link
change notes: Change notes change notes: Change notes
change id: Change ID change id: Change ID
@@ -1050,6 +1076,12 @@ error:
file not found package like: file not found package like:
沒有找到文件:'%s' 在 '%s' 文件包中 沒有找到文件:'%s' 在 '%s' 文件包中
如果你嘗試從別的文件包中打開文件, 使用以下格式"/package/filename" 如果你嘗試從別的文件包中打開文件, 使用以下格式"/package/filename"
#TODO: Localize
file not found package like init:
File not found: '%s' in package '%s'
If this folder is empty or unused, delete it.
#TODO: Localize
package name parse error: Unable to parse package name '%s'
file parse error: file parse error:
處理文件發生錯誤:'%s' 處理文件發生錯誤:'%s'
%s %s
@@ -1128,7 +1160,9 @@ error:
# image stuff # image stuff
coordinates for blending overlap: 坐標混合重疊 coordinates for blending overlap: 坐標混合重疊
#TODO: Localize #TODO: Localize
blending different sizes: Images used for blending must have the same size in function '%s' 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)
#TODO: Localize #TODO: Localize
negative image width: Image with zero or negative width created in function '%s' negative image width: Image with zero or negative width created in function '%s'
#TODO: Localize #TODO: Localize
+36 -2
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8 mse version: 2.6.0
installer group: Magic Set Editor/translations/danish installer group: Magic Set Editor/translations/danish
full name: Dansk (Danish) full name: Dansk (Danish)
version: 2026-02-28 version: 2026-02-28
@@ -56,6 +56,8 @@ menu:
next card: Vælg &Næste Kort PgDn next card: Vælg &Næste Kort PgDn
search cards: &Søg kort Ctrl+K search cards: &Søg kort Ctrl+K
add card: &Tilføj Kort Ctrl+Enter 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... add cards: Tilføj &Flere Kort...
remove card: &Slet Valgte Kort remove card: &Slet Valgte Kort
#TODO: Localize #TODO: Localize
@@ -214,6 +216,8 @@ help:
next card: Vælger det næste kort i listen next card: Vælger det næste kort i listen
search cards: Filtrer kortlisten ved hjælp af søgetermer search cards: Filtrer kortlisten ved hjælp af søgetermer
add card: Tilføler et nyt, tomt kort til listen 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 add cards: Tilføjer flere kort til listen
remove card: Sletter det valgte kort fra sættet! remove card: Sletter det valgte kort fra sættet!
#TODO: Localize #TODO: Localize
@@ -477,6 +481,8 @@ tooltip:
# cards toolbar # cards toolbar
add card: Tilføj kort add card: Tilføj kort
#TODO: Localize
add card double: Add double faced card
remove card: Fjern valgte kort remove card: Fjern valgte kort
#TODO: Localize #TODO: Localize
link card: Link cards to selected card link card: Link cards to selected card
@@ -624,6 +630,16 @@ label:
stylesheet not found: stylesheet not found:
Sættet du har åbner bruger stilen "%s". Sættet du har åbner bruger stilen "%s".
Denne stil er ikke i dit system, vælg venligst et alternativ. Denne stil er ikke i dit system, vælg venligst et alternativ.
#TODO: Localize
searching online: Searching online...
#TODO: Localize
searching online fail: Not found online
#TODO: Localize
found online downloading: Found online! Downloading...
#TODO: Localize
found online installing: Found online! Installing...
#TODO: Localize
found online fail: Installation failed
# preferences dialog # preferences dialog
language: Sprog language: Sprog
@@ -774,6 +790,8 @@ label:
installable version: seneste version: installable version: seneste version:
installer size: Størrelse: installer size: Størrelse:
installer status: Status: installer status: Status:
#TODO: Localize
folder name: Folder name:
no version: - no version: -
#TODO: Localize #TODO: Localize
@@ -906,10 +924,16 @@ button:
upgrade package: &Opdatér upgrade package: &Opdatér
reinstall package: Gen&installér reinstall package: Gen&installér
remove package: &Fjern remove package: &Fjern
#TODO: Localize
keep group: Keep Group As Is
install group: &Installér Alt install group: &Installér Alt
upgrade group: &Opgradér Alt upgrade group: &Opgradér Alt
remove group: &Fjern Alt remove group: &Fjern Alt
# stylesheet not found dialog
#TODO: Localize
find package online: Search Online
############################################################## Titles in the GUI ############################################################## Titles in the GUI
title: title:
# window titles # window titles
@@ -999,6 +1023,8 @@ action:
# cards # cards
#TODO: Localize Section #TODO: Localize Section
reorder cards: Reorder cards reorder cards: Reorder cards
#TODO: Localize
update card: Update card
change link: Change link change link: Change link
change notes: Change notes change notes: Change notes
change id: Change ID change id: Change ID
@@ -1074,6 +1100,12 @@ error:
file not found package like: file not found package like:
File not found: '%s' in package '%s' File not found: '%s' in package '%s'
If you are trying to open a file from another package, use "/package/filename" If you are trying to open a file from another package, use "/package/filename"
#TODO: Localize
file not found package like init:
File not found: '%s' in package '%s'
If this folder is empty or unused, delete it.
#TODO: Localize
package name parse error: Unable to parse package name '%s'
file parse error: file parse error:
Error while parsing file: '%s' Error while parsing file: '%s'
%s %s
@@ -1154,7 +1186,9 @@ error:
#TODO: Localize #TODO: Localize
coordinates for blending overlap: Coordinates for blending overlap. Space them out. coordinates for blending overlap: Coordinates for blending overlap. Space them out.
#TODO: Localize #TODO: Localize
blending different sizes: Images used for blending must have the same size in function '%s' 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)
#TODO: Localize #TODO: Localize
negative image width: Image with zero or negative width created in function '%s' negative image width: Image with zero or negative width created in function '%s'
#TODO: Localize #TODO: Localize
+30 -10
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8 mse version: 2.6.0
installer group: Magic Set Editor/translations/german installer group: Magic Set Editor/translations/german
full name: Deutsch (German) full name: Deutsch (German)
version: 2026-02-28 version: 2026-02-28
@@ -21,7 +21,7 @@ menu:
export images: Alle Bilder exportieren... export images: Alle Bilder exportieren...
export apprentice: &Karte exportieren... export apprentice: &Karte exportieren...
export mws: Magic &Workstation... export mws: Magic &Workstation...
check updates: Nach Updates schauen... check updates: Aktualisierungen / Neue Stylesheets...
print preview: Druckvorschau... print preview: Druckvorschau...
print: &Drucken... Ctrl+P print: &Drucken... Ctrl+P
reload data: Daten neu laden Ctrl+F5 reload data: Daten neu laden Ctrl+F5
@@ -54,6 +54,7 @@ menu:
next card: Nächste Karte PgDn next card: Nächste Karte PgDn
search cards: Suchkarten Ctrl+K search cards: Suchkarten Ctrl+K
add card: Karte Hinzufügen Ctrl+Enter add card: Karte Hinzufügen Ctrl+Enter
add card double: Doppelseitige Karte hinzufügen Ctrl+Shift+Enter
add cards: Mehrere Karten hinzufügen... add cards: Mehrere Karten hinzufügen...
remove card: Markierte Entfernen Del remove card: Markierte Entfernen Del
add card csv: Karten aus CSV oder TSV hinzufügen... add card csv: Karten aus CSV oder TSV hinzufügen...
@@ -195,7 +196,8 @@ help:
previous card: Wählt die vorherige Karte in der Liste aus previous card: Wählt die vorherige Karte in der Liste aus
next card: Wählt die nächste 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 search cards: Filtert die Kartenliste anhand von Suchbegriffen
add card: Fügt eine neue Karte zur Edition hinzu 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 cards: Fügt mehrere Karten zur Edition hinzu add cards: Fügt mehrere Karten zur Edition hinzu
remove card: Entfernt die gewählte Karte aus der Edition remove card: Entfernt die gewählte Karte aus der Edition
link card: Verknüpft eine oder mehrere Karten mit der ausgewählten Karte link card: Verknüpft eine oder mehrere Karten mit der ausgewählten Karte
@@ -442,6 +444,7 @@ tooltip:
# cards toolbar # cards toolbar
add card: Karte hinzufügen add card: Karte hinzufügen
add card double: Doppelseitige Karte hinzufügen
remove card: Gewählte Karte entfernen remove card: Gewählte Karte entfernen
link card: Karten mit ausgewählter Karte verknüpfen link card: Karten mit ausgewählter Karte verknüpfen
copy card and links: Ausgewählte und verknüpfte Karten kopieren copy card and links: Ausgewählte und verknüpfte Karten kopieren
@@ -578,7 +581,13 @@ label:
# stylesheet not found dialog # stylesheet not found dialog
stylesheet not found: stylesheet not found:
Die ausgewählte Edition benutzt das Stylesheet "%s" . Die ausgewählte Edition benutzt das Stylesheet "%s" .
Leider konnte es nicht gefunden werden. Bitte probieren Sie ein anderes. Dieses Stylesheet wurde auf Ihrem System nicht gefunden.
Bitte wählen Sie eine Alternative oder suchen Sie online danach.
searching online: Online-Suche...
searching online fail: Nicht gefunden
found online downloading: Online gefunden! Wird heruntergeladen...
found online installing: Online gefunden! Wird installiert...
found online fail: Installation fehlgeschlagen
# preferences dialog # preferences dialog
language: Sprache language: Sprache
@@ -709,6 +718,7 @@ label:
installable version: Letzte Version installable version: Letzte Version
installer size: Größe installer size: Größe
installer status: Status: installer status: Status:
folder name: Ordnername:
no version: - no version: -
load image: Doppelklicken Sie, um ein Bild zu laden load image: Doppelklicken Sie, um ein Bild zu laden
@@ -821,15 +831,19 @@ button:
close: &Beenden close: &Beenden
# packages window # packages window
keep package: &Nicht verändern keep package: &Unverändert beibehalten
don't install package: &Nicht installieren don't install package: &Nicht installieren
install package: &Installieren install package: &Installieren
upgrade package: &Upgraden upgrade package: &Aktualisieren
reinstall package: Neu &installieren reinstall package: Neu &installieren
remove package: &Entfernen remove package: &Entfernen
install group: &Installiere alle keep group: Gruppe unverändert beibehalten
upgrade group: &Upgrade alle install group: Gruppe installieren/aktualisieren
remove group: &Entferne alle upgrade group: Gruppe aktualisieren
remove group: Gruppe entfernen
# stylesheet not found dialog
find package online: Online Suchen
############################################################## Titles in the GUI ############################################################## Titles in the GUI
title: title:
@@ -909,6 +923,7 @@ title:
action: action:
# cards # cards
reorder cards: Karten neu anordnen reorder cards: Karten neu anordnen
update card: Karte aktualisieren
change link: Link ändern change link: Link ändern
change notes: Notizen ändern change notes: Notizen ändern
change id: ID ändern change id: ID ändern
@@ -978,6 +993,10 @@ error:
file not found package like: file not found package like:
Datei nicht gefunden: '%s' im Package '%s' Datei nicht gefunden: '%s' im Package '%s'
Wenn Sie versuchen sollten, die Datei von einem anderen Package zu laden, verwenden Sie "/package/filename" Wenn Sie versuchen sollten, die Datei von einem anderen Package zu laden, verwenden Sie "/package/filename"
file not found package like init:
Datei nicht gefunden: '%s' im Package '%s'
Wenn dieser Ordner leer oder nicht verwendet ist, löschen Sie ihn.
package name parse error: Packagename '%s' konnte nicht analysiert werden.
file parse error: file parse error:
Fehler beim Parsen von Datei: '%s' Fehler beim Parsen von Datei: '%s'
%s %s
@@ -1047,7 +1066,8 @@ error:
# image stuff # image stuff
coordinates for blending overlap: Die Koordinaten für die Überblendung überlappen sich. 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. 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)
negative image width: Bild mit Breite Null oder negativer Breite, erstellt in der Funktion '%s' 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' 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. can't load image: Bild konnte nicht geladen werden. Stelle sicher, dass das tatsächliche Format des Bildes mit der gespeicherten Dateiendung übereinstimmt.
+29 -9
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8 mse version: 2.6.0
installer group: Magic Set Editor/translations/english installer group: Magic Set Editor/translations/english
full name: English full name: English
version: 2026-02-28 version: 2026-02-28
@@ -21,7 +21,7 @@ menu:
export images: All Card I&mages... export images: All Card I&mages...
export apprentice: &Apprentice... export apprentice: &Apprentice...
export mws: Magic &Workstation... export mws: Magic &Workstation...
check updates: Check &Updates... check updates: Check &Updates / New Styles...
print preview: Print Pre&view... print preview: Print Pre&view...
print: &Print... Ctrl+P print: &Print... Ctrl+P
reload data: Reload Data Ctrl+F5 reload data: Reload Data Ctrl+F5
@@ -54,6 +54,7 @@ menu:
next card: Select &Next Card PgDn next card: Select &Next Card PgDn
search cards: &Search Cards Ctrl+K search cards: &Search Cards Ctrl+K
add card: &Add Card Ctrl+Enter add card: &Add Card Ctrl+Enter
add card double: &Add Double Faced Card Ctrl+Shift+Enter
add cards: Add &Multiple Cards... add cards: Add &Multiple Cards...
remove card: &Delete Selected Card remove card: &Delete Selected Card
add card csv: Add Cards from CSV or TSV... add card csv: Add Cards from CSV or TSV...
@@ -196,6 +197,7 @@ help:
next card: Selects the next card in the list next card: Selects the next card in the list
search cards: Filter the card list using search terms search cards: Filter the card list using search terms
add card: Add a new, blank, card to this set 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 add cards: Add multiple cards to the set
remove card: Delete the selected card from this set remove card: Delete the selected card from this set
link card: Link one or more cards to the selected card link card: Link one or more cards to the selected card
@@ -443,6 +445,7 @@ tooltip:
# cards toolbar # cards toolbar
add card: Add card add card: Add card
add card double: Add double faced card
remove card: Remove selected card remove card: Remove selected card
link card: Link cards to selected card link card: Link cards to selected card
copy card and links: Copy selected cards and linked cards copy card and links: Copy selected cards and linked cards
@@ -579,7 +582,13 @@ label:
# stylesheet not found dialog # stylesheet not found dialog
stylesheet not found: stylesheet not found:
The set you are trying to open uses the stylesheet "%s". The set you are trying to open uses the stylesheet "%s".
This stylesheet is not found on your system, please select an alternative. This stylesheet is not found on your system.
Please select an alternative, or look for it online.
searching online: Searching online...
searching online fail: Not found online
found online downloading: Found online! Downloading...
found online installing: Found online! Installing...
found online fail: Installation failed
# preferences dialog # preferences dialog
language: Language language: Language
@@ -708,6 +717,7 @@ label:
installable version: Latest version: installable version: Latest version:
installer size: Size: installer size: Size:
installer status: Status: installer status: Status:
folder name: Folder name:
no version: - no version: -
load image: Double click to load image load image: Double click to load image
@@ -822,15 +832,19 @@ button:
close: &Close close: &Close
# packages window # packages window
keep package: &Don't change keep package: Keep As Is
don't install package: &Don't install don't install package: &Don't Install
install package: &Install install package: &Install
upgrade package: &Update upgrade package: &Update
reinstall package: Re&install reinstall package: Re&install
remove package: &Remove remove package: &Remove
install group: &Install All keep group: Keep Group As Is
upgrade group: &Upgrade All install group: &Install/Update Group
remove group: &Remove All upgrade group: &Update Group
remove group: &Remove Group
# stylesheet not found dialog
find package online: Search Online
############################################################## Titles in the GUI ############################################################## Titles in the GUI
title: title:
@@ -910,6 +924,7 @@ title:
action: action:
# cards # cards
reorder cards: Reorder cards reorder cards: Reorder cards
update card: Update card
change link: Change link change link: Change link
change notes: Change notes change notes: Change notes
change id: Change ID change id: Change ID
@@ -979,6 +994,10 @@ error:
file not found package like: file not found package like:
File not found: '%s' in package '%s' File not found: '%s' in package '%s'
If you are trying to open a file from another package, use "/package/filename" If you are trying to open a file from another package, use "/package/filename"
file not found package like init:
File not found: '%s' in package '%s'
If this folder is empty or unused, delete it.
package name parse error: Unable to parse package name '%s'
file parse error: file parse error:
Error while parsing file: '%s' Error while parsing file: '%s'
%s %s
@@ -1048,7 +1067,8 @@ error:
# image stuff # image stuff
coordinates for blending overlap: Coordinates for blending overlap. Space them out. 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' 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)
negative image width: Image with zero or negative width created 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' 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. can't load image: Failed to load image. Ensure the image's actual format matches its saved extension.
+36 -2
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8 mse version: 2.6.0
installer group: Magic Set Editor/translations/spanish installer group: Magic Set Editor/translations/spanish
full name: Español (Spanish) full name: Español (Spanish)
version: 2026-02-28 version: 2026-02-28
@@ -54,6 +54,8 @@ menu:
next card: Seleccionar &carta siguiente PgDn next card: Seleccionar &carta siguiente PgDn
search cards: &Buscar Cartas Ctrl+K search cards: &Buscar Cartas Ctrl+K
add card: &Añadir carta Ctrl+Enter 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... add cards: Añadir &múltiples cartas...
remove card: &Borrar carta seleccionada remove card: &Borrar carta seleccionada
#TODO: Localize #TODO: Localize
@@ -208,6 +210,8 @@ help:
next card: Selecciona la carta siguiente en la lista next card: Selecciona la carta siguiente en la lista
search cards: Filtra la lista de cartas usando términos de búsqueda 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 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 add cards: Añade múltiples cartas al Set
remove card: Borra la carta seleccionada de este Set remove card: Borra la carta seleccionada de este Set
#TODO: Localize #TODO: Localize
@@ -468,6 +472,8 @@ tooltip:
# cards toolbar # cards toolbar
add card: Añadir carta add card: Añadir carta
#TODO: Localize
add card double: Add double faced card
remove card: Eliminar carta seleccionada remove card: Eliminar carta seleccionada
#TODO: Localize #TODO: Localize
link card: Link cards to selected card link card: Link cards to selected card
@@ -615,6 +621,16 @@ label:
stylesheet not found: stylesheet not found:
El Set que estás intentando abrir usa el estilo "%s". El Set que estás intentando abrir usa el estilo "%s".
Este estilo no se encuentra en tu sistema, por favor selecciona otro. Este estilo no se encuentra en tu sistema, por favor selecciona otro.
#TODO: Localize
searching online: Searching online...
#TODO: Localize
searching online fail: Not found online
#TODO: Localize
found online downloading: Found online! Downloading...
#TODO: Localize
found online installing: Found online! Installing...
#TODO: Localize
found online fail: Installation failed
# preferences dialog # preferences dialog
language: Idioma language: Idioma
@@ -759,6 +775,8 @@ label:
installable version: Última versión: installable version: Última versión:
installer size: Tamaño: installer size: Tamaño:
installer status: Estado: installer status: Estado:
#TODO: Localize
folder name: Folder name:
no version: - no version: -
#TODO: Localize #TODO: Localize
@@ -891,10 +909,16 @@ button:
upgrade package: &Actualizar upgrade package: &Actualizar
reinstall package: R&einstalar reinstall package: R&einstalar
remove package: &Eliminar remove package: &Eliminar
#TODO: Localize
keep group: Keep Group As Is
install group: Instalar &Todos install group: Instalar &Todos
upgrade group: A&ctualizar Todos upgrade group: A&ctualizar Todos
remove group: Q&uitar Todos remove group: Q&uitar Todos
# stylesheet not found dialog
#TODO: Localize
find package online: Search Online
############################################################## Titles in the GUI ############################################################## Titles in the GUI
title: title:
# window titles # window titles
@@ -982,6 +1006,8 @@ action:
# cards # cards
#TODO: Localize Section #TODO: Localize Section
reorder cards: Reorder cards reorder cards: Reorder cards
#TODO: Localize
update card: Update card
change link: Change link change link: Change link
change notes: Change notes change notes: Change notes
change id: Change ID change id: Change ID
@@ -1053,6 +1079,12 @@ error:
file not found package like: file not found package like:
Archivo no encontrado: '%s' en el paquete '%s' Archivo no encontrado: '%s' en el paquete '%s'
Si estás intentando abrir un archivo de otro paquete, usa "/package/filename" Si estás intentando abrir un archivo de otro paquete, usa "/package/filename"
#TODO: Localize
file not found package like init:
File not found: '%s' in package '%s'
If this folder is empty or unused, delete it.
#TODO: Localize
package name parse error: Unable to parse package name '%s'
file parse error: file parse error:
Error mientras se analizaba el archivo: '%s' Error mientras se analizaba el archivo: '%s'
%s %s
@@ -1131,7 +1163,9 @@ error:
# image stuff # image stuff
coordinates for blending overlap: Coordenadas para la mezcla (blending) solapada coordinates for blending overlap: Coordenadas para la mezcla (blending) solapada
#TODO: Localize #TODO: Localize
blending different sizes: Images used for blending must have the same size in function '%s' 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)
#TODO: Localize #TODO: Localize
negative image width: Image with zero or negative width created in function '%s' negative image width: Image with zero or negative width created in function '%s'
#TODO: Localize #TODO: Localize
+115 -95
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8 mse version: 2.6.0
installer group: Magic Set Editor/translations/french installer group: Magic Set Editor/translations/french
full name: Français (French) full name: Français (French)
version: 2026-02-28 version: 2026-02-28
@@ -21,7 +21,7 @@ menu:
export images: Toutes les I&mages de Carte... export images: Toutes les I&mages de Carte...
export apprentice: &Apprentice... export apprentice: &Apprentice...
export mws: Magic &Workstation... export mws: Magic &Workstation...
check updates: Vérifier les Mises à Jo&ur... check updates: Mises à Jo&ur / Nouveaux Styles...
print preview: Aperçu d'&Impression... print preview: Aperçu d'&Impression...
print: &Imprimer... Ctrl+P print: &Imprimer... Ctrl+P
reload data: Recharger les Données Ctrl+F5 reload data: Recharger les Données Ctrl+F5
@@ -54,8 +54,9 @@ menu:
next card: Carte &Suivante PgDn next card: Carte &Suivante PgDn
search cards: Rechercher dans les Cartes Ctrl+K search cards: Rechercher dans les Cartes Ctrl+K
add card: &Ajouter une Carte Ctrl+Enter add card: &Ajouter une Carte Ctrl+Enter
add card double: Ajouter une Carte recto-verso Ctrl+Shift+Enter
add cards: Ajouter &plusieurs Cartes... 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 csv: Ajouter plusieurs Cartes depuis un CSV ou TSV...
add card json: Ajouter plusieurs Cartes depuis un JSON... add card json: Ajouter plusieurs Cartes depuis un JSON...
link card: &Lier des Cartes à la Carte sélectionnée... link card: &Lier des Cartes à la Carte sélectionnée...
@@ -159,15 +160,15 @@ help:
save set as directory: Sauver le Set en tant que dossier non compressé save set as directory: Sauver le Set en tant que dossier non compressé
export: Exporter le Set... export: Exporter le Set...
export html: Exporter le Set en tant que fichier HTML export html: Exporter le Set en tant que fichier HTML
export image: Exporter la carte selectionnée en tant qu'image export image: Exporter la Carte selectionnée en tant qu'image
export images: Exporter toutes les cartes en tant qu'images export images: Exporter toutes les Cartes en tant qu'images
export apprentice: Exporter le Set pour être utilisé avec Apprentice export apprentice: Exporter le Set pour être utilisé avec Apprentice
export mws: Exporter le Set pour être utilisé avec Magic Workstation 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 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 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) 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 preview: Voir les Cartes telles qu'elles vont être imprimées
print: Imprimer les cartes de ce Set print: Imprimer les Cartes de ce Set
reload data: Recharger tous les Templates ainsi que le 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 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 exit: Quitter Magic Set Editor; Vous demandera de sauvegarder le Set
@@ -176,37 +177,38 @@ help:
undo: Annuler la dernière action undo: Annuler la dernière action
redo: Refaire la dernière action redo: Refaire la dernière action
cut: Couper le texte selectionné dans le presse-papier 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 cut keyword: Couper le Mot-clef selectionné dans le presse-papier
copy: Copier le texte 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 copy keyword: Copier le Mot-clef selectionné dans le presse-papier
paste: Insérer le texte depuis 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 paste keyword: Insérer le mot_clef depuis le presse-papier
select all: Sélectionner tout le texte 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 find next: Rechercher l'occurrence suivante
replace: Remplacer l'occurrence replace: Remplacer l'occurrence
auto replace: Quel texte devra être automatiquement remplacé? auto replace: Quel texte devra être automatiquement remplacé?
preferences: Changer la configuration de Magic Set Editor preferences: Changer la configuration de Magic Set Editor
# cards menu # cards menu
previous card: Choisir la carte précédente dans la liste previous card: Choisir la Carte précédente dans la liste
next card: Choisir la carte suivante 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 search cards: Filtrer la liste des Carte à l'aide de termes de recherche
add card: Ajouter une nouvelle carte vierge au Set add card: Ajouter une nouvelle Carte vierge au Set
add cards: Ajouter plusieurs cartes au Set add card double: Ajouter une nouvelle Carte vierge avec un verso au Set
remove card: Supprimer la carte sélectionnée du Set add cards: Ajouter plusieurs Cartes au Set
link card: Lier des cartes à la carte sélectionnée remove card: Supprimer la Carte sélectionnée du Set
copy card and links: Copier les cartes sélectionnées ainsi que toutes leurs cartes liées link card: Lier des Cartes à la Carte sélectionnée
bulk modify: Modifier beaucoup de cartes d'un coup copy card and links: Copier les Cartes sélectionnées ainsi que toutes leurs Cartes liées
orientation: Orientation de la carte visualisée bulk modify: Modifier beaucoup de Cartes d'un coup
rotate card: Tourner la carte de 90° dans le sens des aiguilles d'une montre orientation: Orientation de la Carte visualisée
rotate 0: Afficher la carte dans son sens original rotate card: Tourner la Carte de 90° dans le sens des aiguilles d'une montre
rotate 270: Afficher la carte tournée dans le sens des aiguilles d'une montre rotate 0: Afficher la Carte dans son sens original
rotate 90: Afficher la carte tournée dans le sens inverse des aiguilles d'une montre rotate 270: Afficher la Carte tournée dans le sens des aiguilles d'une montre
rotate 180: Afficher la carte à l'envers 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 card list columns: Choisir quelles colonnes doivent être affichées et dans quel ordre
# keywords menu # keywords menu
@@ -231,10 +233,10 @@ help:
no spelling suggestions: Il n'y a pas de suggestions pour corriger cette faute no spelling suggestions: Il n'y a pas de suggestions pour corriger cette faute
# graph menu # graph menu
pie: Un graphique en secteurs, l'épaisseur de la tranche 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 bar: Un graphique à barres, la hauteur de la barre indique le nombre de Cartes
stack: Un graphique à barres empilées 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 scatter pie: Un nuage de points où chaque point est un petit graphique en secteurs
# console menu # console menu
@@ -242,12 +244,12 @@ help:
# window menu # window menu
new window: Ouvrir une nouvelle fenêtre pour éditer le même Set 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... 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 keywords tab: Définir des Mots-clefs supplémentaires pour le Set
stats tab: Voir les statistiques des 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 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 console tab: Afficher les messages d'erreurs et executer des scripts
# help menu # help menu
@@ -261,12 +263,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. 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 # 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 # cards panel
collapse notes: Cacher les notes des cartes collapse notes: Cacher les notes des Cartes
expand notes: Afficher 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. 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 # 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. 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.
@@ -284,7 +286,7 @@ help:
pour que le changement prenne effet. pour que le changement prenne effet.
zoom export: zoom export:
(Quand l'option est décochée, les (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.) taille et dans leur rotation normale.)
# apprentice export # apprentice export
@@ -367,7 +369,7 @@ tool:
console tab: Console console tab: Console
# cards toolbar # 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 1: %s Au total
stats card counts 2: %s Dans le filtre, %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 card counts 2: %s Dans la sélection, %s Au total
@@ -442,11 +444,12 @@ tooltip:
redo: Rétablir%s redo: Rétablir%s
# cards toolbar # cards toolbar
add card: Ajouter une carte add card: Ajouter une Carte
remove card: Supprimer la carte sélectionnée add card double: Ajouter une Carte recto-verso
link card: Lier des cartes à la carte sélectionnée remove card: Supprimer la Carte sélectionnée
copy card and links: Copier les cartes sélectionnées et leurs cartes liées link card: Lier des Cartes à la Carte sélectionnée
rotate card: Tourner la carte copy card and links: Copier les Cartes sélectionnées et leurs Cartes liées
rotate card: Tourner la Carte
# keywords toolbar # keywords toolbar
add keyword: Ajouter un Mot-clef add keyword: Ajouter un Mot-clef
@@ -513,7 +516,7 @@ tooltip:
label: label:
## app window items labels ## app window items labels
# cards panel # cards panel
card notes: Notes de carte: card notes: Notes de Carte:
# keywords panel # keywords panel
search keywords: Recherche dans les mots-clefs (Ctrl+K) search keywords: Recherche dans les mots-clefs (Ctrl+K)
@@ -542,18 +545,18 @@ label:
custom link selected: Générateur, Face Avant, Composant d'Assimilation, etc... 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 linked: Jeton, Face Arrière, Résultat d'Assimilation, etc...
custom link undefined: Non Défini 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: selected card: Carte sélectionnée:
linked cards: Cartes liées: 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 modification dialog
bulk modify selection: Quelles cartes doivent être modifiées: bulk modify selection: Quelles Cartes doivent être modifiées:
bulk modify all: Toutes les cartes bulk modify all: Toutes les Cartes
bulk modify filtered: Les cartes actuellement filtrées bulk modify filtered: Les Cartes actuellement filtrées
bulk modify selected: Les cartes actuellement sélectionnées bulk modify selected: Les Cartes actuellement sélectionnées
bulk modify predicate: Les cartes qui vérifient un critère 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 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 predicate example: Example (petites créatures de M:tG):
bulk modify field: Quelle valeur doit être modifiée: bulk modify field: Quelle valeur doit être modifiée:
bulk modify mod description: Que doit être la nouvelle valeur: bulk modify mod description: Que doit être la nouvelle valeur:
@@ -572,14 +575,20 @@ label:
# new set dialog # new set dialog
game type: &Type de jeu: game type: &Type de jeu:
style type: &Style des carte: style type: &Style des Carte:
search game list: Filtrer les jeux search game list: Filtrer les jeux
search stylesheet list: Filtrer les Styles search stylesheet list: Filtrer les Styles
# stylesheet not found dialog # stylesheet not found dialog
stylesheet not found: stylesheet not found:
Le Set que vous essayez d'ouvrir utilise le Style "%s". Le Set que vous essayez d'ouvrir utilise le Style "%s".
Ce Style n'a pas été trouvé sur votre ordinateur. Selectionnez une alternative. Ce Style n'a pas été trouvé sur votre ordinateur.
Selectionnez une alternative, ou cherchez en ligne.
searching online: Recherche en ligne...
searching online fail: Introuvable en ligne
found online downloading: Trouvé en ligne! Téléchargement...
found online installing: Trouvé en ligne! Installation...
found online fail: Échec de linstallation
# preferences dialog # preferences dialog
language: Langue language: Langue
@@ -589,7 +598,7 @@ label:
dark mode no: Mode clair dark mode no: Mode clair
dark mode yes: Mode sombre dark mode yes: Mode sombre
app language: Langue de l'interface utilisateur (App Language) app language: Langue de l'interface utilisateur (App Language)
card display: Affichage des cartes card display: Affichage des Cartes
zoom: &Zoom: zoom: &Zoom:
import: Import import: Import
export: &Export export: &Export
@@ -602,7 +611,7 @@ label:
external programs: Programmes externes external programs: Programmes externes
apprentice: &Apprentice: apprentice: &Apprentice:
apprentice exe: Executable 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: import desc: Lors de l'importation d'images pour les illustrations:
internal scale desc: internal scale desc:
Taille à laquelle stocker les images en interne. Taille à laquelle stocker les images en interne.
@@ -621,8 +630,8 @@ label:
# card select / image export dialogs # card select / image export dialogs
select cards: Cartes à exporter select cards: Cartes à exporter
select cards print: Selectionner les cartes à imprimer select cards print: Selectionner les Cartes à imprimer
selected card count: %s cartes seront exportées. selected card count: %s Cartes seront exportées.
filename format: &Format: filename format: &Format:
filename conflicts: &Gestion des doublons de fichiers: filename conflicts: &Gestion des doublons de fichiers:
export filenames: Nom des fichiers export filenames: Nom des fichiers
@@ -646,7 +655,7 @@ label:
# JSON import dialog # JSON import dialog
add card json type: Type de fichier JSON: add card json type: Type de fichier JSON:
add card json custom: Fichier JSON customisé 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: add card json file: Chemin du fichier:
# image slicer dialog # image slicer dialog
@@ -709,17 +718,18 @@ label:
installable version: Dernière version: installable version: Dernière version:
installer size: Taille: installer size: Taille:
installer status: État: installer status: État:
folder name: Dossier:
no version: - no version: -
load image: Double-cliquer pour charger une image load image: Double-cliquer pour charger une image
# print dialog # print dialog
put space between cards: Ajouter un espace entre les cartes? put space between cards: Ajouter un espace entre les Cartes?
spacing print: Espace entre les cartes en millimètres spacing print: Espace entre les Cartes en millimètres
bleed print: Marge de fond perdu en millimètres bleed print: Marge de fond perdu en millimètres
cutter lines print: Ajouter des lignes de découpe? cutter lines print: Ajouter des lignes de découpe?
cutter lines all: Toutes 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 cutter lines none: Aucune
## symbol editor ## symbol editor
@@ -732,8 +742,8 @@ button:
link select: Sélectionner link select: Sélectionner
# style panel # style panel
use for all cards: Utiliser pour toutes les c&artes use for all cards: Utiliser pour toutes les C&artes
use custom styling options: Options &spécifique à cette carte use custom styling options: Options &spécifique à cette Carte
# set info panel # set info panel
edit symbol: Éditer edit symbol: Éditer
@@ -773,9 +783,9 @@ button:
Ajoutez une marge de Ajoutez une marge de
fond perdu grossière fond perdu grossière
notes export: notes export:
Exporter les notes de la carte à Exporter les notes de la Carte à
l'intérieur des Métadonnées de l'image 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 check now: &Vérifier maintenant
always: Toujours always: Toujours
every 5 startups: Tous les 5 démarrages every 5 startups: Tous les 5 démarrages
@@ -801,7 +811,7 @@ button:
export entire set: Set complet export entire set: Set complet
export generated packs: Packs générés export generated packs: Packs générés
export custom cards selection: Sélection personalisée 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 all: Sélectionner &toutes
select none: Sélectionner &aucune select none: Sélectionner &aucune
overwrite: Ecraser les anciens fichiers overwrite: Ecraser les anciens fichiers
@@ -824,12 +834,16 @@ button:
keep package: &Ne pas modifier keep package: &Ne pas modifier
don't install package: &Ne pas installer don't install package: &Ne pas installer
install package: &Installer install package: &Installer
upgrade package: &Upgrader upgrade package: &Mettre à jour
reinstall package: Ré&installer reinstall package: Ré&installer
remove package: &Supprimer remove package: &Supprimer
install group: &Installer Tout keep group: &Ne pas modifier le groupe
upgrade group: &Upgrader Tout install group: &Installer/Mettre à jour le groupe
remove group: &Supprimer Tout upgrade group: &Mettre à jour le groupe
remove group: &Supprimer le groupe
# stylesheet not found dialog
find package online: Chercher En Ligne
############################################################## Titles in the GUI ############################################################## Titles in the GUI
title: title:
@@ -908,12 +922,13 @@ title:
############################################################## Action (undo/redo) names ############################################################## Action (undo/redo) names
action: action:
# cards # cards
reorder cards: Réorganiser les cartes reorder cards: Réorganiser les Cartes
update card: Mettre à jour la Carte
change link: Modifier le lien change link: Modifier le lien
change notes: Modifier les notes change notes: Modifier les notes
change id: Modifier l'ID change id: Modifier l'ID
change style: Modifier le style 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é use custom style: Utiliser un style personnalisé
show reminder text: Afficher le texte de rappel show reminder text: Afficher le texte de rappel
hide reminder text: Masquer le texte de rappel hide reminder text: Masquer le texte de rappel
@@ -978,6 +993,10 @@ error:
file not found package like: file not found package like:
Fichier non trouvé: '%s' dans le package '%s' Fichier non trouvé: '%s' dans le package '%s'
Si vous essayez d'ouvrir un fichier d'un autre package, utilisez "/package/fichier" Si vous essayez d'ouvrir un fichier d'un autre package, utilisez "/package/fichier"
file not found package like init:
Fichier non trouvé: '%s' dans le package '%s'
Si ce dossier est vide ou inutilisé, supprimez-le.
package name parse error: Impossible d'analyser le nom du package '%s'.
file parse error: file parse error:
Erreur lors de la lecture du fichier: '%s' Erreur lors de la lecture du fichier: '%s'
%s %s
@@ -1010,7 +1029,7 @@ error:
no field with name: Impossible de trouver le champ de %s nommé '%s' 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 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 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 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') 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é add card csv file not found: Impossible de trouver ou charger le fichier CSV ou TSV spécifié
@@ -1047,14 +1066,15 @@ error:
# image stuff # image stuff
coordinates for blending overlap: Les coordonnées pour le mélange sont superposées. Espacez-les. 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'. 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)
negative image width: Image de largeur nulle ou négative créée par 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' 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. 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. symbol image has alpha: Pour un résultat optimal, l'image doit être en noir et blanc sans transparence.
# error from files # 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. 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'. 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 no game specified: Pas de jeu spécifié pour le %s
@@ -1084,15 +1104,15 @@ error:
no updates: Il n'y a pas de mises à jour disponibles. no updates: Il n'y a pas de mises à jour disponibles.
# card linking # 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: 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. 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: 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. 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'. 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 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. 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.) 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. 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 input: Carte d'input introuvable.
could not find linked: Carte liée (linked_card) introuvable. could not find linked: Carte liée (linked_card) introuvable.
@@ -1102,11 +1122,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 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 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 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 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: Aucune Carte à modifier.
bulk modify no cards verify: Aucune carte ne correspond au critère. bulk modify no cards verify: Aucune Carte ne correspond au critère.
bulk modify nothing: Aucune carte n'a été modifiée. bulk modify nothing: Aucune Carte n'a été modifiée.
bulk modify success: Nombre de cartes modifiées avec succès : %s bulk modify success: Nombre de Cartes modifiées avec succès : %s
# web request # web request
web request failed: Échec de la requête Web web request failed: Échec de la requête Web
@@ -1167,9 +1187,9 @@ type:
stylesheet: stylesheet stylesheet: stylesheet
export template: modèle d'export export template: modèle d'export
symbol: symbole symbol: symbole
card: carte card: Carte
cards: cartes cards: Cartes
extra card: extra carte extra card: extra Carte
field: champ field: champ
style: style style: style
styling: style styling: style
@@ -1177,8 +1197,8 @@ type:
keyword: mot-clef keyword: mot-clef
keywords: mots-clefs keywords: mots-clefs
pack: type de pack pack: type de pack
card region: région de carte card region: région de Carte
card regions: régions de carte card regions: régions de Carte
# symbol editor shapes # symbol editor shapes
shape: forme shape: forme
+29 -9
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8 mse version: 2.6.0
installer group: Magic Set Editor/translations/italian installer group: Magic Set Editor/translations/italian
full name: Italiano (Italian) full name: Italiano (Italian)
version: 2026-02-28 version: 2026-02-28
@@ -21,7 +21,7 @@ menu:
export images: I&mmagini Carte... export images: I&mmagini Carte...
export apprentice: &Apprentice... export apprentice: &Apprentice...
export mws: Magic &Workstation... export mws: Magic &Workstation...
check updates: Cerca aggiornamenti... check updates: Aggiornamenti / Nuovi Stili...
print preview: Anteprima di S&tampa... print preview: Anteprima di S&tampa...
print: &Stampa... Ctrl+P print: &Stampa... Ctrl+P
reload data: Ricarica dati Ctrl+F5 reload data: Ricarica dati Ctrl+F5
@@ -54,6 +54,7 @@ menu:
next card: Seleziona &carta successiva PgDn next card: Seleziona &carta successiva PgDn
search cards: Cerca carte Ctrl+K search cards: Cerca carte Ctrl+K
add card: &Aggiungi carta Ctrl+Enter add card: &Aggiungi carta Ctrl+Enter
add card double: Aggiungi carta fronte-retro Ctrl+Shift+Enter
add cards: Aggiungi &carte Multiple... add cards: Aggiungi &carte Multiple...
remove card: &Rimuovi carta Del remove card: &Rimuovi carta Del
add card csv: Aggiungi carte da CSV o TSV... add card csv: Aggiungi carte da CSV o TSV...
@@ -196,6 +197,7 @@ help:
next card: Seleziona la prossima carta della lista next card: Seleziona la prossima carta della lista
search cards: Filtra l'elenco delle carte utilizzando i termini di ricerca search cards: Filtra l'elenco delle carte utilizzando i termini di ricerca
add card: Aggiunge una nuova carta vuota al set 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 add cards: Aggiunge carte multiple al set
remove card: Cancella la carta selezionata dal set remove card: Cancella la carta selezionata dal set
link card: Collega una o più carte alla carta selezionata link card: Collega una o più carte alla carta selezionata
@@ -443,6 +445,7 @@ tooltip:
# cards toolbar # cards toolbar
add card: Aggiungi carta add card: Aggiungi carta
add card double: Aggiungi carta fronte-retro
remove card: Rimuovi carta selezionata remove card: Rimuovi carta selezionata
link card: Collega alcune carte alla carta selezionata link card: Collega alcune carte alla carta selezionata
copy card and links: Copia le carte selezionate e tutte le carte collegate copy card and links: Copia le carte selezionate e tutte le carte collegate
@@ -579,7 +582,13 @@ label:
# stylesheet not found dialog # stylesheet not found dialog
stylesheet not found: stylesheet not found:
Il set che stai cercando di aprire usa lo stile "%s". Il set che stai cercando di aprire usa lo stile "%s".
Questo stile non è stato trovato sul tuo sistema, scegli un'alternativa. Questo stile non è stato trovato sul tuo sistema.
Seleziona un'alternativa o cercalo online.
searching online: Ricerca online in corso...
searching online fail: Non trovato online
found online downloading: Trovato online! Download in corso...
found online installing: Trovato online! Installazione in corso...
found online fail: Installazione non riuscita
# preferences dialog # preferences dialog
language: Lingua language: Lingua
@@ -709,6 +718,7 @@ label:
installable version: Ultima versione: installable version: Ultima versione:
installer size: Dimesioni: installer size: Dimesioni:
installer status: Stato: installer status: Stato:
folder name: Nome:
no version: - no version: -
load image: Fai doppio clic per caricare un'immagine load image: Fai doppio clic per caricare un'immagine
@@ -821,15 +831,19 @@ button:
close: &Chiudi close: &Chiudi
# packages window # packages window
keep package: &Non modificare keep package: &Mantieni così com'è
don't install package: &Non installare don't install package: &Non installare
install package: &Installa install package: &Installa
upgrade package: Aggiorna (&U) upgrade package: Aggiorna
reinstall package: Re&installa reinstall package: Re&installa
remove package: &Rimuovi remove package: &Rimuovi
install group: &Installa Tutto keep group: Mantieni il gruppo così com'è
upgrade group: &Upgrade Tutto install group: &Installa/Aggiorna il gruppo
remove group: &Rimuovi Tutto upgrade group: &Aggiorna il gruppo
remove group: &Rimuovi il gruppo
# stylesheet not found dialog
find package online: Cerca online
############################################################## Titles in the GUI ############################################################## Titles in the GUI
title: title:
@@ -909,6 +923,7 @@ title:
action: action:
# cards # cards
reorder cards: Riordina le carte reorder cards: Riordina le carte
update card: Aggiorna la carta
change link: Modifica collegamento change link: Modifica collegamento
change notes: Modifica note change notes: Modifica note
change id: Modifica ID change id: Modifica ID
@@ -978,6 +993,10 @@ error:
file not found package like: file not found package like:
File non trovato: '%s' nel pacchetto '%s' File non trovato: '%s' nel pacchetto '%s'
Se si sta tentando di aprire un file da un altro pacchetto, utilizzare "/package/filename" Se si sta tentando di aprire un file da un altro pacchetto, utilizzare "/package/filename"
file not found package like init:
File non trovato: '%s' nel pacchetto '%s'
Se questa cartella è vuota o inutilizzata, eliminala.
package name parse error: Impossibile analizzare il nome del pacchetto '%s'
file parse error: file parse error:
Errore analizzando il file: '%s' Errore analizzando il file: '%s'
%s %s
@@ -1047,7 +1066,8 @@ error:
# image stuff # image stuff
coordinates for blending overlap: Le coordinate per la fusione si sovrappongono. 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'. 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)
negative image width: Immagine con larghezza zero o negativa creata 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'. 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. can't load image: Impossibile caricare l'immagine. Assicurarsi che il formato effettivo dell'immagine corrisponda all'estensione salvata.
+36 -2
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8 mse version: 2.6.0
installer group: Magic Set Editor/translations/japanese installer group: Magic Set Editor/translations/japanese
full name: 日本語 (Japanese) full name: 日本語 (Japanese)
version: 2026-02-28 version: 2026-02-28
@@ -54,6 +54,8 @@ menu:
next card: 次のカードを選択 PgDn next card: 次のカードを選択 PgDn
search cards: カードの検索 Ctrl+K search cards: カードの検索 Ctrl+K
add card: &カードを追加 Ctrl+Enter add card: &カードを追加 Ctrl+Enter
#TODO: Localize
add card double: &Add Double Faced Card Ctrl+Shift+Enter
add cards: &複数のカードを追加... add cards: &複数のカードを追加...
remove card: &選択したカードを削除 remove card: &選択したカードを削除
#TODO: Localize #TODO: Localize
@@ -208,6 +210,8 @@ help:
next card: リストの次のカードを選択します。 next card: リストの次のカードを選択します。
search cards: 検索語を使用してカードリストをフィルタリングする search cards: 検索語を使用してカードリストをフィルタリングする
add card: 新しいカードを現在のセットに加えます。 add card: 新しいカードを現在のセットに加えます。
#TODO: Localize
add card double: Add a new, blank, card that has a back face to this set
add cards: 複数のカードを現在のセットに加えます。 add cards: 複数のカードを現在のセットに加えます。
remove card: 現在のセットから選ばれたカードを削除します。 remove card: 現在のセットから選ばれたカードを削除します。
#TODO: Localize #TODO: Localize
@@ -467,6 +471,8 @@ tooltip:
# cards toolbar # cards toolbar
add card: カードを追加 add card: カードを追加
#TODO: Localize
add card double: Add double faced card
remove card: 選択したカードを削除 remove card: 選択したカードを削除
#TODO: Localize #TODO: Localize
link card: Link cards to selected card link card: Link cards to selected card
@@ -614,6 +620,16 @@ label:
stylesheet not found: stylesheet not found:
あなたが始めようとしているセットがスタイルシートを使う "%s"。 あなたが始めようとしているセットがスタイルシートを使う "%s"。
このstylesheetがあなたのシステムで見つからないで、選択肢を選んでください。 このstylesheetがあなたのシステムで見つからないで、選択肢を選んでください。
#TODO: Localize
searching online: Searching online...
#TODO: Localize
searching online fail: Not found online
#TODO: Localize
found online downloading: Found online! Downloading...
#TODO: Localize
found online installing: Found online! Installing...
#TODO: Localize
found online fail: Installation failed
# preferences dialog # preferences dialog
language: 言語 language: 言語
@@ -758,6 +774,8 @@ label:
installable version: 最新バージョン installable version: 最新バージョン
installer size: サイズ installer size: サイズ
installer status: 状態 installer status: 状態
#TODO: Localize
folder name: Folder name:
no version: - no version: -
#TODO: Localize #TODO: Localize
@@ -890,10 +908,16 @@ button:
upgrade package: &アップグレード upgrade package: &アップグレード
reinstall package: 再インストール reinstall package: 再インストール
remove package: &取り外す remove package: &取り外す
#TODO: Localize
keep group: Keep Group As Is
install group: すべてインストールする install group: すべてインストールする
upgrade group: すべてアップグレードする upgrade group: すべてアップグレードする
remove group: すべて削除する remove group: すべて削除する
# stylesheet not found dialog
#TODO: Localize
find package online: Search Online
############################################################## Titles in the GUI ############################################################## Titles in the GUI
title: title:
# window titles # window titles
@@ -982,6 +1006,8 @@ action:
# cards # cards
#TODO: Localize Section #TODO: Localize Section
reorder cards: Reorder cards reorder cards: Reorder cards
#TODO: Localize
update card: Update card
change link: Change link change link: Change link
change notes: Change notes change notes: Change notes
change id: Change ID change id: Change ID
@@ -1053,6 +1079,12 @@ error:
file not found package like: file not found package like:
ファイルが見つかりません '%s' パッケージの '%s' ファイルが見つかりません '%s' パッケージの '%s'
しようとしている場合は、別のパッケージからファイルを開くには、使用する "/パッケージ/ファイル名" しようとしている場合は、別のパッケージからファイルを開くには、使用する "/パッケージ/ファイル名"
#TODO: Localize
file not found package like init:
File not found: '%s' in package '%s'
If this folder is empty or unused, delete it.
#TODO: Localize
package name parse error: Unable to parse package name '%s'
file parse error: file parse error:
ファイルをパースし誤り: '%s' ファイルをパースし誤り: '%s'
%s %s
@@ -1131,7 +1163,9 @@ error:
# image stuff # image stuff
coordinates for blending overlap: オーバーラップを混ぜることのための座標 coordinates for blending overlap: オーバーラップを混ぜることのための座標
#TODO: Localize #TODO: Localize
blending different sizes: Images used for blending must have the same size in function '%s' 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)
#TODO: Localize #TODO: Localize
negative image width: Image with zero or negative width created in function '%s' negative image width: Image with zero or negative width created in function '%s'
#TODO: Localize #TODO: Localize
+36 -2
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8 mse version: 2.6.0
installer group: Magic Set Editor/translations/korean installer group: Magic Set Editor/translations/korean
full name: 한국어 (Korean) full name: 한국어 (Korean)
version: 2026-02-28 version: 2026-02-28
@@ -54,6 +54,8 @@ menu:
next card: 다음 카드 PgDn next card: 다음 카드 PgDn
search cards: &카드 검색 Ctrl+K search cards: &카드 검색 Ctrl+K
add card: &카드 추가 Ctrl+Enter add card: &카드 추가 Ctrl+Enter
#TODO: Localize
add card double: &Add Double Faced Card Ctrl+Shift+Enter
add cards: &여러 카드 추가... add cards: &여러 카드 추가...
remove card: &카드 삭제 remove card: &카드 삭제
#TODO: Localize #TODO: Localize
@@ -208,6 +210,8 @@ help:
next card: 목록에서 다음 카드를 선택합니다. next card: 목록에서 다음 카드를 선택합니다.
search cards: 검색어를 사용하여 카드 목록 필터링 search cards: 검색어를 사용하여 카드 목록 필터링
add card: 이 세트에 새로운 빈 카드를 추가하세요. add card: 이 세트에 새로운 빈 카드를 추가하세요.
#TODO: Localize
add card double: Add a new, blank, card that has a back face to this set
add cards: 세트에 여러 카드 추가 add cards: 세트에 여러 카드 추가
remove card: 이 세트에서 선택한 카드를 삭제하세요. remove card: 이 세트에서 선택한 카드를 삭제하세요.
#TODO: Localize #TODO: Localize
@@ -473,6 +477,8 @@ tooltip:
# cards toolbar # cards toolbar
add card: 카드 추가 add card: 카드 추가
#TODO: Localize
add card double: Add double faced card
remove card: 선택한 카드 삭제 remove card: 선택한 카드 삭제
#TODO: Localize #TODO: Localize
link card: Link cards to selected card link card: Link cards to selected card
@@ -619,6 +625,16 @@ label:
stylesheet not found: stylesheet not found:
열려고 하는 세트는 스타일시트 '%s'을 사용합니다. 열려고 하는 세트는 스타일시트 '%s'을 사용합니다.
이 스타일시트를 시스템에서 찾을 수 없습니다. 대체 스타일을 선택하십시오. 이 스타일시트를 시스템에서 찾을 수 없습니다. 대체 스타일을 선택하십시오.
#TODO: Localize
searching online: Searching online...
#TODO: Localize
searching online fail: Not found online
#TODO: Localize
found online downloading: Found online! Downloading...
#TODO: Localize
found online installing: Found online! Installing...
#TODO: Localize
found online fail: Installation failed
# preferences dialog # preferences dialog
language: 언어 language: 언어
@@ -764,6 +780,8 @@ label:
installable version: 최신 버전: installable version: 최신 버전:
installer size: 크기: installer size: 크기:
installer status: 상태: installer status: 상태:
#TODO: Localize
folder name: Folder name:
no version: - no version: -
#TODO: Localize #TODO: Localize
@@ -896,10 +914,16 @@ button:
upgrade package: 업데이트 upgrade package: 업데이트
reinstall package: 재설치 reinstall package: 재설치
remove package: 제거하다 remove package: 제거하다
#TODO: Localize
keep group: Keep Group As Is
install group: 모두 설치 install group: 모두 설치
upgrade group: 모두 업그레이드 upgrade group: 모두 업그레이드
remove group: 모두 제거 remove group: 모두 제거
# stylesheet not found dialog
#TODO: Localize
find package online: Search Online
############################################################## Titles in the GUI ############################################################## Titles in the GUI
title: title:
# window titles # window titles
@@ -988,6 +1012,8 @@ action:
# cards # cards
#TODO: Localize Section #TODO: Localize Section
reorder cards: Reorder cards reorder cards: Reorder cards
#TODO: Localize
update card: Update card
change link: Change link change link: Change link
change notes: Change notes change notes: Change notes
change id: Change ID change id: Change ID
@@ -1059,6 +1085,12 @@ error:
file not found package like: file not found package like:
파일을 찾을 수 없습니다: '%s' 패키지에 '%s' 파일을 찾을 수 없습니다: '%s' 패키지에 '%s'
다른 패키지의 파일을 열려고 하는 경우 다음을 사용하십시오. "/패키지 이름/파일 이름" 다른 패키지의 파일을 열려고 하는 경우 다음을 사용하십시오. "/패키지 이름/파일 이름"
#TODO: Localize
file not found package like init:
File not found: '%s' in package '%s'
If this folder is empty or unused, delete it.
#TODO: Localize
package name parse error: Unable to parse package name '%s'
file parse error: file parse error:
파일을 구문 분석하는 중 오류가 발생했습니다.: '%s' 파일을 구문 분석하는 중 오류가 발생했습니다.: '%s'
%s %s
@@ -1137,7 +1169,9 @@ error:
# image stuff # image stuff
coordinates for blending overlap: 블렌딩 오버랩을 위한 좌표 coordinates for blending overlap: 블렌딩 오버랩을 위한 좌표
#TODO: Localize #TODO: Localize
blending different sizes: Images used for blending must have the same size in function '%s' 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)
#TODO: Localize #TODO: Localize
negative image width: Image with zero or negative width created in function '%s' negative image width: Image with zero or negative width created in function '%s'
#TODO: Localize #TODO: Localize
+36 -2
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8 mse version: 2.6.0
installer group: Magic Set Editor/translations/polski installer group: Magic Set Editor/translations/polski
full name: Polski (Polish) full name: Polski (Polish)
version: 2026-02-28 version: 2026-02-28
@@ -64,6 +64,8 @@ menu:
#TODO: Localize #TODO: Localize
search cards: &Search Cards Ctrl+K search cards: &Search Cards Ctrl+K
add card: &Dodaj Kartę Ctrl+Enter add card: &Dodaj Kartę Ctrl+Enter
#TODO: Localize
add card double: &Add Double Faced Card Ctrl+Shift+Enter
add cards: Dodaj &Wiele Kart... add cards: Dodaj &Wiele Kart...
remove card: &Usuń Wybraną Kartę remove card: &Usuń Wybraną Kartę
#TODO: Localize #TODO: Localize
@@ -227,6 +229,8 @@ help:
#TODO: Localize #TODO: Localize
search cards: Filter the card list using search terms search cards: Filter the card list using search terms
add card: Dodaj nową, pustą kartę do zestawu 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 add cards: Dodaj wiele kart do zestawu
remove card: Usuń wybraną kartę z zestawu remove card: Usuń wybraną kartę z zestawu
#TODO: Localize #TODO: Localize
@@ -502,6 +506,8 @@ tooltip:
# cards toolbar # cards toolbar
add card: Dodaj kartę add card: Dodaj kartę
#TODO: Localize
add card double: Add double faced card
remove card: Usuń wybraną kartę remove card: Usuń wybraną kartę
#TODO: Localize #TODO: Localize
link card: Link cards to selected card link card: Link cards to selected card
@@ -654,6 +660,16 @@ label:
stylesheet not found: stylesheet not found:
Zestaw który próbujesz otworzyć używa stylu z arkusz "%s". Zestaw który próbujesz otworzyć używa stylu z arkusz "%s".
Nie udało się znaleźć tego arkuszu, wybierz jakiś inny. Nie udało się znaleźć tego arkuszu, wybierz jakiś inny.
#TODO: Localize
searching online: Searching online...
#TODO: Localize
searching online fail: Not found online
#TODO: Localize
found online downloading: Found online! Downloading...
#TODO: Localize
found online installing: Found online! Installing...
#TODO: Localize
found online fail: Installation failed
# preferences dialog # preferences dialog
language: Język language: Język
@@ -808,6 +824,8 @@ label:
installable version: Najnowsza wersja: installable version: Najnowsza wersja:
installer size: Rozmiar: installer size: Rozmiar:
installer status: Stan: installer status: Stan:
#TODO: Localize
folder name: Folder name:
no version: - no version: -
#TODO: Localize #TODO: Localize
@@ -944,10 +962,16 @@ button:
upgrade package: &Uaktualnij upgrade package: &Uaktualnij
reinstall package: Zainstaluj &ponownie reinstall package: Zainstaluj &ponownie
remove package: &Usuń remove package: &Usuń
#TODO: Localize
keep group: Keep Group As Is
install group: &Instaluj wszystkie install group: &Instaluj wszystkie
upgrade group: &Uaktualnij wszystkie upgrade group: &Uaktualnij wszystkie
remove group: &Usuń wszystkie remove group: &Usuń wszystkie
# stylesheet not found dialog
#TODO: Localize
find package online: Search Online
############################################################## Titles in the GUI ############################################################## Titles in the GUI
title: title:
# window titles # window titles
@@ -1037,6 +1061,8 @@ action:
# cards # cards
#TODO: Localize Section #TODO: Localize Section
reorder cards: Reorder cards reorder cards: Reorder cards
#TODO: Localize
update card: Update card
change link: Change link change link: Change link
change notes: Change notes change notes: Change notes
change id: Change ID change id: Change ID
@@ -1109,6 +1135,12 @@ error:
file not found package like: file not found package like:
Nie znaleziono pliku: '%s' w paczce '%s' Nie znaleziono pliku: '%s' w paczce '%s'
Jeśli próbujesz otworzyć plik z innej paczki, użyj "/paczka/plik" Jeśli próbujesz otworzyć plik z innej paczki, użyj "/paczka/plik"
#TODO: Localize
file not found package like init:
File not found: '%s' in package '%s'
If this folder is empty or unused, delete it.
#TODO: Localize
package name parse error: Unable to parse package name '%s'
file parse error: file parse error:
Błąd parsowania pliku: '%s' Błąd parsowania pliku: '%s'
%s %s
@@ -1187,7 +1219,9 @@ error:
# image stuff # image stuff
coordinates for blending overlap: Współrzędne scalania (blending) nachodzą na siebie coordinates for blending overlap: Współrzędne scalania (blending) nachodzą na siebie
#TODO: Localize #TODO: Localize
blending different sizes: Images used for blending must have the same size in function '%s' 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)
#TODO: Localize #TODO: Localize
negative image width: Image with zero or negative width created in function '%s' negative image width: Image with zero or negative width created in function '%s'
#TODO: Localize #TODO: Localize
+33 -13
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8 mse version: 2.6.0
installer group: Magic Set Editor/translations/portuguese brazilian installer group: Magic Set Editor/translations/portuguese brazilian
full name: Português do Brasil (Brazilian Portuguese) full name: Português do Brasil (Brazilian Portuguese)
version: 2026-02-28 version: 2026-02-28
@@ -21,7 +21,7 @@ menu:
export images: Todas as I&magens dos Cards... export images: Todas as I&magens dos Cards...
export apprentice: &Apprentice... export apprentice: &Apprentice...
export mws: Magic &Workstation... export mws: Magic &Workstation...
check updates: &Atualizações... check updates: &Atualizações / Novas folhas de estilo...
print preview: V&isualização da Imprensão... print preview: V&isualização da Imprensão...
print: &Imprimir... Ctrl+P print: &Imprimir... Ctrl+P
reload data: Recarregar Dados Ctrl+F5 reload data: Recarregar Dados Ctrl+F5
@@ -54,6 +54,7 @@ menu:
next card: Selecionar Próximo ca&rd PgDn next card: Selecionar Próximo ca&rd PgDn
search cards: &Procurar Cards Ctrl+K search cards: &Procurar Cards Ctrl+K
add card: &Adicionar Card Ctrl+Enter add card: &Adicionar Card Ctrl+Enter
add card double: &Adicionar Card de dupla face Ctrl+Shift+Enter
add cards: Adicionar &Multiplos Cards... add cards: Adicionar &Multiplos Cards...
remove card: &Deletar Card Selecionado remove card: &Deletar Card Selecionado
add card csv: Adicionar Cards de um arquivo CSV ou TSV... add card csv: Adicionar Cards de um arquivo CSV ou TSV...
@@ -194,8 +195,9 @@ help:
# cards menu # cards menu
previous card: Seleciona o Card anterior da lista. previous card: Seleciona o Card anterior da lista.
next card: Seleciona o próximo Card 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: 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. add cards: Adicione multiplos Cards à esta Edição.
remove card: Apaga o Card selecionado desta Edição. remove card: Apaga o Card selecionado desta Edição.
link card: Vincular um ou mais Cards à Card selecionado link card: Vincular um ou mais Cards à Card selecionado
@@ -444,6 +446,7 @@ tooltip:
# cards toolbar # cards toolbar
add card: Adiciona um Card add card: Adiciona um Card
add card double: Adicionar um Card de dupla face
remove card: Remove o Card selecionado remove card: Remove o Card selecionado
link card: Vincular Cards ao Card selecionado link card: Vincular Cards ao Card selecionado
copy card and links: Copiar Cards selecionados e seus Cards vinculados copy card and links: Copiar Cards selecionados e seus Cards vinculados
@@ -579,8 +582,14 @@ label:
# stylesheet not found dialog # stylesheet not found dialog
stylesheet not found: stylesheet not found:
A Edição está tentando abrir a folha de estilo "%s". A Edição está tentando abrir a folha de estilo "%s".
Esta folha de estilo não é compatível com o sistema padrão. Por favor escolha uma folha de estilo alternativa. Esta folha de estilo não é compatível com o sistema padrão.
Selecione uma alternativa ou procure-a online.
searching online: Pesquisando online...
searching online fail: Não encontrado online
found online downloading: Encontrado online! Baixando...
found online installing: Encontrado online! Instalando...
found online fail: Falha na instalação
# preferences dialog # preferences dialog
language: Linguagem language: Linguagem
@@ -710,6 +719,7 @@ label:
installable version: Última versão: installable version: Última versão:
installer size: Dimenções: installer size: Dimenções:
installer status: Status: installer status: Status:
folder name: Nome da pasta:
no version: - no version: -
load image: Clique duas vezes para carregar uma imagem load image: Clique duas vezes para carregar uma imagem
@@ -822,15 +832,19 @@ button:
close: &Fechar close: &Fechar
# packages window # packages window
keep package: Não& alterar keep package: Manter como está
don't install package: Não& instalar don't install package: Não& instalar
install package: &Instalar install package: &Instalar
upgrade package: &Atualizações upgrade package: &Atualizar
reinstall package: Re&instalar reinstall package: Re&instalar
remove package: &Remover remove package: &Remover
install group: &Instalar Tudo keep group: &Manter o grupo como está
upgrade group: &Atualizar tudo install group: &Instalar/Atualizar o grupo
remove group: &Remover tudo upgrade group: &Atualizar o grupo
remove group: &Remover o grupo
# stylesheet not found dialog
find package online: Pesquisar online
############################################################## Titles in the GUI ############################################################## Titles in the GUI
title: title:
@@ -910,6 +924,7 @@ title:
action: action:
# cards # cards
reorder cards: Reordenar Cards reorder cards: Reordenar Cards
update card: Atualizar Card
change link: Alterar link change link: Alterar link
change notes: Alterar notas change notes: Alterar notas
change id: Alterar ID change id: Alterar ID
@@ -975,10 +990,14 @@ action:
############################################################## Error messages ############################################################## Error messages
error: error:
# file related # file related
file not found: O arquivo não foi encontrado: '%s' em pacotes '%s' file not found: O arquivo não foi encontrado: '%s' no pacote '%s'
file not found package like: file not found package like:
Arquivo nao encontrado: '%s' in package '%s' Arquivo nao encontrado: '%s' no pacote '%s'
Se você está tentando abrir um arquivo de outro pacote, use "/package/filename" Se você está tentando abrir um arquivo de outro pacote, use "/package/filename"
file not found package like init:
Arquivo nao encontrado: '%s' no pacote '%s'
Se esta pasta estiver vazia ou não for usada, exclua-a.
package name parse error: Não foi possível analisar o nome do pacote '%s'
file parse error: file parse error:
Erro ao analisar o arquivo: '%s' Erro ao analisar o arquivo: '%s'
%s %s
@@ -1048,7 +1067,8 @@ error:
# image stuff # image stuff
coordinates for blending overlap: As coordenadas para a mistura se sobrepõem. 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'. 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)
negative image width: Imagem com largura zero ou negativa criada 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' 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. can't load image: Falha ao carregar a imagem. Verifique se o formato real da imagem corresponde à extensão salva.
+36 -2
View File
@@ -1,4 +1,4 @@
mse version: 2.5.8 mse version: 2.6.0
installer group: Magic Set Editor/translations/russian installer group: Magic Set Editor/translations/russian
full name: Русский (Russian) full name: Русский (Russian)
version: 2026-02-28 version: 2026-02-28
@@ -55,6 +55,8 @@ menu:
next card: Следующая карта PgDn next card: Следующая карта PgDn
search cards: Найти карты Ctrl+K search cards: Найти карты Ctrl+K
add card: Добавить карту Ctrl+Enter add card: Добавить карту Ctrl+Enter
#TODO: Localize
add card double: &Add Double Faced Card Ctrl+Shift+Enter
add cards: Добавить несколько карт... add cards: Добавить несколько карт...
remove card: Удалить выделенную карту remove card: Удалить выделенную карту
#TODO: Localize #TODO: Localize
@@ -219,6 +221,8 @@ help:
next card: Выбрать следующую карту в списке next card: Выбрать следующую карту в списке
search cards: Отфильтруйте список карточек с помощью условий поиска search cards: Отфильтруйте список карточек с помощью условий поиска
add card: Добавить новую карту в текущий сет add card: Добавить новую карту в текущий сет
#TODO: Localize
add card double: Add a new, blank, card that has a back face to this set
add cards: Добавить несколько новых карт в текущий сет add cards: Добавить несколько новых карт в текущий сет
remove card: Удалить выбранную карту из текущего сета remove card: Удалить выбранную карту из текущего сета
#TODO: Localize #TODO: Localize
@@ -490,6 +494,8 @@ tooltip:
# cards toolbar # cards toolbar
add card: Добавить карту add card: Добавить карту
#TODO: Localize
add card double: Add double faced card
remove card: Удалить выделенную карту remove card: Удалить выделенную карту
#TODO: Localize #TODO: Localize
link card: Link cards to selected card link card: Link cards to selected card
@@ -642,6 +648,16 @@ label:
stylesheet not found: stylesheet not found:
Сет, который ты пытаешься открыть использует стиль "%s". Сет, который ты пытаешься открыть использует стиль "%s".
Этого стиля не найдено в твоей системе, выбери альтернативу Этого стиля не найдено в твоей системе, выбери альтернативу
#TODO: Localize
searching online: Searching online...
#TODO: Localize
searching online fail: Not found online
#TODO: Localize
found online downloading: Found online! Downloading...
#TODO: Localize
found online installing: Found online! Installing...
#TODO: Localize
found online fail: Installation failed
# preferences dialog # preferences dialog
language: Язык language: Язык
@@ -798,6 +814,8 @@ label:
installable version: Последняя версия: installable version: Последняя версия:
installer size: Размер: installer size: Размер:
installer status: Статус: installer status: Статус:
#TODO: Localize
folder name: Folder name:
no version: - no version: -
#TODO: Localize #TODO: Localize
@@ -932,10 +950,16 @@ button:
upgrade package: Обновить upgrade package: Обновить
reinstall package: Переустановить reinstall package: Переустановить
remove package: Удалить remove package: Удалить
#TODO: Localize
keep group: Keep Group As Is
install group: Установить все install group: Установить все
upgrade group: Обновить все upgrade group: Обновить все
remove group: Удалить все remove group: Удалить все
# stylesheet not found dialog
#TODO: Localize
find package online: Search Online
############################################################## Titles in the GUI ############################################################## Titles in the GUI
title: title:
# window titles # window titles
@@ -1025,6 +1049,8 @@ action:
# cards # cards
#TODO: Localize Section #TODO: Localize Section
reorder cards: Reorder cards reorder cards: Reorder cards
#TODO: Localize
update card: Update card
change link: Change link change link: Change link
change notes: Change notes change notes: Change notes
change id: Change ID change id: Change ID
@@ -1102,6 +1128,12 @@ error:
file not found package like: file not found package like:
File not found: '%s' in package '%s' File not found: '%s' in package '%s'
If you are trying to open a file from another package, use "/package/filename" If you are trying to open a file from another package, use "/package/filename"
#TODO: Localize
file not found package like init:
File not found: '%s' in package '%s'
If this folder is empty or unused, delete it.
#TODO: Localize
package name parse error: Unable to parse package name '%s'
file parse error: file parse error:
Error while parsing file: '%s' Error while parsing file: '%s'
%s %s
@@ -1182,7 +1214,9 @@ error:
#TODO: Localize #TODO: Localize
coordinates for blending overlap: Coordinates for blending overlap. Space them out. coordinates for blending overlap: Coordinates for blending overlap. Space them out.
#TODO: Localize #TODO: Localize
blending different sizes: Images used for blending must have the same size in function '%s' 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)
#TODO: Localize #TODO: Localize
negative image width: Image with zero or negative width created in function '%s' negative image width: Image with zero or negative width created in function '%s'
#TODO: Localize #TODO: Localize
+16
View File
@@ -0,0 +1,16 @@
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,6 +78,7 @@ 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: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: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:remove_choice]] Remove the given choices from a multiple choice value.
| [[fun:is_default]] Check if a field is in its default state.
! Images <<< ! Images <<<
| [[fun:linear_blend]] Blend two images together using a linear gradient. | [[fun:linear_blend]] Blend two images together using a linear gradient.
@@ -108,6 +109,7 @@ These functions are built into the program, other [[type:function]]s can be defi
! Cards <<< ! Cards <<<
| [[fun:new_card]] Construct a new [[type:card]] object. | [[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: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_styling]] Get the styling data of a [[type:card]].
| [[fun:get_card_stylesheet]] Get the stylesheet of a [[type:card]]. | [[fun:get_card_stylesheet]] Get the stylesheet of a [[type:card]].
@@ -136,4 +138,6 @@ These functions are built into the program, other [[type:function]]s can be defi
| [[fun:assert]] Check a condition for debugging purposes. | [[fun:assert]] Check a condition for debugging purposes.
| [[fun:warning]] Output a warning message. | [[fun:warning]] Output a warning message.
| [[fun:error]] Output an error 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. | [[fun:exists_in_package]] Checks if a file exists in a package.
+10
View File
@@ -0,0 +1,10 @@
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
@@ -0,0 +1,10 @@
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
@@ -0,0 +1,18 @@
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.

After

Width:  |  Height:  |  Size: 546 B

+1
View File
@@ -66,6 +66,7 @@ tool/dark_reminder IMAGE "tool/dark_reminder.png"
tool/no_auto IMAGE "tool/no_auto.png" tool/no_auto IMAGE "tool/no_auto.png"
tool/card_add IMAGE "tool/card_add.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_add_multiple IMAGE "tool/card_add_multiple.png"
tool/card_modify_multiple IMAGE "tool/card_modify_multiple.png" tool/card_modify_multiple IMAGE "tool/card_modify_multiple.png"
tool/card_del IMAGE "tool/card_del.png" tool/card_del IMAGE "tool/card_del.png"
+39 -17
View File
@@ -30,13 +30,6 @@ 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, // 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 // and never because two different cards randomly got assigned the same uid
if (!action.adding) return; 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 // Tally added unique ids
unordered_map<String, CardP> all_added_uids; unordered_map<String, CardP> all_added_uids;
for (size_t pos = 0; pos < action.steps.size(); ++pos) { for (size_t pos = 0; pos < action.steps.size(); ++pos) {
@@ -49,7 +42,7 @@ AddCardAction::AddCardAction(AddingOrRemoving ar, Set& set, const vector<CardP>&
String old_uid = added_pair.first; String old_uid = added_pair.first;
CardP added_card = added_pair.second; CardP added_card = added_pair.second;
// Assign new unique id if necessary // Assign new unique id if necessary
if (all_existing_cards.find(old_uid) == all_existing_cards.end()) continue; if (set.card_uids.find(old_uid) == set.card_uids.end()) continue;
String new_uid = generate_uid(); String new_uid = generate_uid();
added_card->uid = new_uid; added_card->uid = new_uid;
all_added_uids.insert({ new_uid, added_card }); all_added_uids.insert({ new_uid, added_card });
@@ -58,21 +51,22 @@ AddCardAction::AddCardAction(AddingOrRemoving ar, Set& set, const vector<CardP>&
FOR_EACH(linked_pair, linked_pairs) { FOR_EACH(linked_pair, linked_pairs) {
String& linked_uid = linked_pair.first.get(); String& linked_uid = linked_pair.first.get();
if (linked_uid.empty()) continue; if (linked_uid.empty()) continue;
// If it's an added card, replace the link // If it's an added card, update the link
if (all_added_uids.find(linked_uid) != all_added_uids.end()) { if (all_added_uids.find(linked_uid) != all_added_uids.end()) {
all_added_uids.at(linked_uid)->updateLinkedUID(old_uid, new_uid); 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 // Otherwise, if it's an existing card, create an action to copy the link
else if (all_existing_cards.find(linked_uid) != all_existing_cards.end()) { else if (set.card_uids.find(linked_uid) != set.card_uids.end()) {
CardP linked_card = all_existing_cards.at(linked_uid); CardP linked_card = set.card_uids.at(linked_uid);
int linked_index = linked_card->findFreeLink(new_uid, all_existing_uids); int selected_index = linked_card->findUIDLink(old_uid);
if (linked_index < 0) { if (selected_index < 0) continue;
int free_index = linked_card->findFreeLink(new_uid, set.card_uids);
if (free_index < 0) {
queue_message(MESSAGE_WARNING, _ERROR_1_("not enough free links", linked_card->identification())); queue_message(MESSAGE_WARNING, _ERROR_1_("not enough free links", linked_card->identification()));
continue;
} }
else { String selected_relation(linked_card->getLinkedRelation(selected_index));
String relation(linked_card->getLinkedRelation(linked_index)); card_link_actions.push_back(make_intrusive<OneWayLinkCardsAction>(linked_card, new_uid, selected_relation, free_index));
card_link_actions.push_back(make_intrusive<OneWayLinkCardsAction>(linked_card, new_uid, relation, linked_index));
}
} }
} }
} }
@@ -89,6 +83,33 @@ void AddCardAction::perform(bool to_undo) {
for (size_t i = 0; i < card_link_actions.size(); ++i) { for (size_t i = 0; i < card_link_actions.size(); ++i) {
card_link_actions[i]->perform(to_undo); 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);
}
} }
// ----------------------------------------------------------------------------- : Reorder cards // ----------------------------------------------------------------------------- : Reorder cards
@@ -250,6 +271,7 @@ void ChangeCardUIDAction::perform(bool to_undo) {
c->updateLinkedUID(card->uid, uid); c->updateLinkedUID(card->uid, uid);
} }
swap(card->uid, uid); swap(card->uid, uid);
set.buildUIDMap();
} }
// ----------------------------------------------------------------------------- : Pack types // ----------------------------------------------------------------------------- : Pack types
+12
View File
@@ -50,6 +50,18 @@ public:
vector<ActionP> card_link_actions; 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 // ----------------------------------------------------------------------------- : Reorder cards
/// Change the position of a card in the card list by swapping two cards /// Change the position of a card in the card list by swapping two cards
+3 -1
View File
@@ -401,7 +401,9 @@ String BulkAction::getName(bool to_undo) const {
} }
void BulkAction::perform(bool to_undo) { void BulkAction::perform(bool to_undo) {
FOR_EACH(action, actions) { size_t size = actions.size();
for (size_t i = 0 ; i < size ; ++i) {
ActionP& action = actions[to_undo ? size - i - 1 : i];
action->perform(to_undo); action->perform(to_undo);
set->actions.tellListeners(*action, to_undo); set->actions.tellListeners(*action, to_undo);
} }
+8 -4
View File
@@ -26,17 +26,21 @@ IMPLEMENT_REFLECTION_NO_SCRIPT(AddCardsScript) {
void AddCardsScript::perform(Set& set, vector<CardP>& out) { void AddCardsScript::perform(Set& set, vector<CardP>& out) {
// Perform script // Perform script
Context& ctx = set.getContext(); Context& ctx = set.getContext();
if (enabled.hasBeenRead()) {
enabled.update(ctx);
if (!enabled()) return;
}
ScriptValueP result = script.invoke(ctx); ScriptValueP result = script.invoke(ctx);
// Add cards to out // Add cards to out
ScriptValueP it = result->makeIterator(); ScriptValueP it = result->makeIterator();
while (ScriptValueP item = it->next()) { while (ScriptValueP item = it->next()) {
CardP card = from_script<CardP>(item); CardP new_card = from_script<CardP>(item);
// is this a new card? // is this a new card?
if (contains(set.cards,card) || contains(out,card)) { if (contains(set.cards,new_card) || contains(out,new_card)) {
// make copy // make copy
card = make_intrusive<Card>(*card); new_card = make_intrusive<Card>(&set, new_card);
} }
out.push_back(card); out.push_back(new_card);
} }
} }
+125 -46
View File
@@ -44,6 +44,37 @@ Card::Card(Game& game)
data.init(game.card_fields); 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 { String Card::identification() const {
// an identifying field // an identifying field
FOR_EACH_CONST(v, data) { FOR_EACH_CONST(v, data) {
@@ -67,7 +98,7 @@ bool Card::contains(QuickFilterPart const& query) const {
return false; return false;
} }
vector<int> Card::findFreeLinks(vector<String>& linked_uids, const unordered_set<String>& all_existing_uids) { vector<int> Card::findFreeLinks(vector<String>& linked_uids, const unordered_map<String, CardP>& all_existing_uids) {
vector<int> freeIndexes; vector<int> freeIndexes;
int count = min(4, (int)linked_uids.size()); int count = min(4, (int)linked_uids.size());
LINK_PAIRS(linked_pairs, this); LINK_PAIRS(linked_pairs, this);
@@ -109,7 +140,7 @@ vector<int> Card::findFreeLinks(vector<String>& linked_uids, const unordered_set
} }
return freeIndexes; return freeIndexes;
} }
int Card::findFreeLink(const String& linked_uid, const unordered_set<String>& all_existing_uids) { int Card::findFreeLink(const String& linked_uid, const unordered_map<String, CardP>& all_existing_uids) {
vector<String> linked_uids { linked_uid }; vector<String> linked_uids { linked_uid };
return findFreeLinks(linked_uids, all_existing_uids)[0]; return findFreeLinks(linked_uids, all_existing_uids)[0];
} }
@@ -155,12 +186,26 @@ void Card::updateLinkedUID(const String& old_uid, const String& new_uid) {
if (index >= 0) getLinkedUID(index) = 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> 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> other_cards; vector<CardP> other_cards;
vector<int> indexes = findRelationLinks(linked_relation); vector<int> indexes = findRelationLinks(linked_relation);
for (size_t i = 0; i < indexes.size(); ++i) { for (size_t i = 0; i < indexes.size(); ++i) {
String& linked_uid = getLinkedUID(indexes[i]); String& linked_uid = getLinkedUID(indexes[i]);
CardP other_card = getUIDCard(cards, linked_uid); CardP other_card = getUIDCard(set, linked_uid);
if (other_card) other_cards.push_back(other_card); if (other_card) other_cards.push_back(other_card);
else if (erase_if_no_card) { else if (erase_if_no_card) {
linked_uid = _(""); linked_uid = _("");
@@ -169,51 +214,76 @@ vector<CardP> Card::getLinkedRelationCards(const vector<CardP>& cards, const Str
} }
return other_cards; 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) { //vector<pair<CardP, String>> Card::getLinkedCards(const vector<CardP>& cards) {
unordered_map<String, String> links{ // unordered_map<String, String> links{
{ linked_card_1, linked_relation_1 }, // { linked_card_1, linked_relation_1 },
{ linked_card_2, linked_relation_2 }, // { linked_card_2, linked_relation_2 },
{ linked_card_3, linked_relation_3 }, // { linked_card_3, linked_relation_3 },
{ linked_card_4, linked_relation_4 } // { 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>> linked_cards; vector<pair<CardP, String>> linked_cards;
FOR_EACH(other_card, cards) { CardP other_card_1 = getUIDCard(set, linked_card_1);
if (links.find(other_card->uid) != links.end()) { if (other_card_1) {
linked_cards.push_back(make_pair(other_card, links.at(other_card->uid))); 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));
} }
return linked_cards; return linked_cards;
} }
vector<pair<CardP, String>> Card::getLinkedCards(const Set& set) {
return getLinkedCards(set.cards);
}
CardP Card::getLinkedOtherFaceCard(const vector<CardP>& cards) { //CardP Card::getLinkedOtherFaceCard(const vector<CardP>& cards) {
unordered_set<String> faces; // unordered_set<String> faces;
if (linked_relation_1 == _("Front Face") || linked_relation_1 == _("Back Face")) faces.emplace(linked_card_1); // 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_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_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); // if (linked_relation_4 == _("Front Face") || linked_relation_4 == _("Back Face")) faces.emplace(linked_card_4);
FOR_EACH(other_card, cards) { // FOR_EACH(other_card, cards) {
if (faces.find(other_card->uid) != faces.end()) return other_card; // 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;
} }
return nullptr; 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) { void Card::addLink(const Set& set, CardP& linked_card, const String& selected_relation, const String& linked_relation) {
unordered_set<String> all_existing_uids; int index = findFreeLink(linked_card->uid, set.card_uids);
FOR_EACH(card, set.cards) {
all_existing_uids.insert(card->uid);
}
int index = findFreeLink(linked_card->uid, all_existing_uids);
if (index < 0) { if (index < 0) {
queue_message(MESSAGE_ERROR, _ERROR_1_("not enough free links", identification())); queue_message(MESSAGE_ERROR, _ERROR_1_("not enough free links", identification()));
return; return;
@@ -221,7 +291,7 @@ void Card::addLink(const Set& set, CardP& linked_card, const String& selected_re
getLinkedUID(index) = linked_card->uid; getLinkedUID(index) = linked_card->uid;
getLinkedRelation(index) = linked_relation; getLinkedRelation(index) = linked_relation;
index = linked_card->findFreeLink(uid, all_existing_uids); index = linked_card->findFreeLink(uid, set.card_uids);
if (index < 0) { if (index < 0) {
queue_message(MESSAGE_ERROR, _ERROR_1_("not enough free links", linked_card->identification())); queue_message(MESSAGE_ERROR, _ERROR_1_("not enough free links", linked_card->identification()));
} }
@@ -246,15 +316,19 @@ void Card::removeLink(const CardP& linked_card)
} }
} }
CardP Card::getUIDCard(const vector<CardP>& cards, const String& uid) { //CardP Card::getUIDCard(const vector<CardP>& cards, const String& uid) {
FOR_EACH(card, cards) { // FOR_EACH(card, cards) {
if (card->uid == uid) return card; // 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;
} }
return nullptr; return nullptr;
} }
CardP Card::getUIDCard(const Set& set, const String& uid) {
return getUIDCard(set.cards, uid);
}
IndexMap<FieldP, ValueP>& Card::extraDataFor(const StyleSheet& stylesheet) { IndexMap<FieldP, ValueP>& Card::extraDataFor(const StyleSheet& stylesheet) {
return extra_data.get(stylesheet.name(), stylesheet.extra_card_fields); return extra_data.get(stylesheet.name(), stylesheet.extra_card_fields);
@@ -301,7 +375,12 @@ void reflect_version_check(GetDefaultMember& handler, const Char* key, intrusive
IMPLEMENT_REFLECTION(Card) { IMPLEMENT_REFLECTION(Card) {
REFLECT(stylesheet); REFLECT(stylesheet);
reflect_version_check(handler, _("stylesheet_version"), stylesheet); if (Handler::isReading) {
REFLECT_NO_SCRIPT(stylesheet_version);
}
else {
reflect_version_check(handler, _("stylesheet_version"), stylesheet);
}
REFLECT(has_styling); REFLECT(has_styling);
if (has_styling) { if (has_styling) {
if (stylesheet) { if (stylesheet) {
+10 -6
View File
@@ -35,6 +35,8 @@ public:
Card(); Card();
/// Creates a card using the given game /// Creates a card using the given game
Card(Game& game); Card(Game& game);
/// Copy constructor, makes a deep copy
Card(Set* set, const CardP& card);
/// The game this card is made for /// The game this card is made for
Game* game; Game* game;
@@ -61,6 +63,8 @@ public:
/// Alternative style to use for this card /// Alternative style to use for this card
/** Optional; if not set use the card style from the set */ /** Optional; if not set use the card style from the set */
StyleSheetP stylesheet; StyleSheetP stylesheet;
/// What version of the stylesheet was this card using when it was last saved?
Version stylesheet_version;
/// Alternative options to use for this card, for this card's stylesheet /// Alternative options to use for this card, for this card's stylesheet
/** Optional; if not set use the styling data from the set. /** 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 * If stylesheet is set then contains data for the this->stylesheet, otherwise for set->stylesheet
@@ -106,8 +110,8 @@ public:
} }
/// Find the index of a free link slot to write to. Returns -1 if not found. /// Find the index of a free link slot to write to. Returns -1 if not found.
int findFreeLink (const String& linked_uid, const unordered_set<String>& all_existing_uids); int findFreeLink (const String& linked_uid, const unordered_map<String, CardP>& all_existing_uids);
vector<int> findFreeLinks(vector<String>& linked_uids, const unordered_set<String>& all_existing_uids); vector<int> findFreeLinks(vector<String>& linked_uids, const unordered_map<String, CardP>& all_existing_uids);
/// Find the index of a link slot that references the linked_uid. Returns -1 if not found. /// Find the index of a link slot that references the linked_uid. Returns -1 if not found.
int findUIDLink(const String& linked_uid); int findUIDLink(const String& linked_uid);
@@ -125,18 +129,18 @@ public:
//void updateLinkedRelation(const String& old_relation, const String& new_relation); //void updateLinkedRelation(const String& old_relation, const String& new_relation);
/// Get the card with the given uid. /// 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); static CardP getUIDCard(const Set& set, const String& uid);
/// Get all the cards linked to this card with the given relation. /// 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); vector<CardP> getLinkedRelationCards(const Set& set, const String& linked_relation, bool erase_if_no_card = true);
/// Get all the cards linked to this card. /// 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); vector<pair<CardP, String>> getLinkedCards(const Set& set);
/// Get the back face or front face of this card. /// 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); CardP getLinkedOtherFaceCard(const Set& set);
/// Link a card to this card. /// Link a card to this card.
+4
View File
@@ -305,6 +305,10 @@ bool Value::equals(const Value* that) {
return this == that; return this == that;
} }
bool Value::isDefault() {
return false;
}
bool Value::update(Context& ctx) { bool Value::update(Context& ctx) {
updateAge(); updateAge();
updateSortValue(ctx); updateSortValue(ctx);
+2
View File
@@ -256,6 +256,8 @@ public:
/// Convert this value to a string for use in tables /// Convert this value to a string for use in tables
virtual String toString() const = 0; virtual String toString() const = 0;
/// Check if this value is in the default state
virtual bool isDefault();
/// Apply scripts to this value, return true if the value has changed /// Apply scripts to this value, return true if the value has changed
virtual bool update(Context& ctx); virtual bool update(Context& ctx);
/// This value has been updated by an action /// This value has been updated by an action
+5
View File
@@ -318,6 +318,11 @@ ChoiceValue::ChoiceValue(const ChoiceFieldP& field, bool initial_first_choice)
String ChoiceValue::toString() const { String ChoiceValue::toString() const {
return value(); return value();
} }
bool ChoiceValue::isDefault() {
return value.isDefault();
}
bool ChoiceValue::update(Context& ctx) { bool ChoiceValue::update(Context& ctx) {
bool change = field().default_script.invokeOnDefault(ctx, value) bool change = field().default_script.invokeOnDefault(ctx, value)
| field(). script.invokeOn(ctx, value); | field(). script.invokeOn(ctx, value);
+2
View File
@@ -200,6 +200,8 @@ public:
ValueType value; /// The name of the selected choice ValueType value; /// The name of the selected choice
bool isDefault() override;
bool update(Context&) override; bool update(Context&) override;
}; };
+5
View File
@@ -111,6 +111,11 @@ String ColorValue::toString() const {
} }
return _("<color>"); return _("<color>");
} }
bool ColorValue::isDefault() {
return value.isDefault();
}
bool ColorValue::update(Context& ctx) { bool ColorValue::update(Context& ctx) {
bool change = field().default_script.invokeOnDefault(ctx, value) bool change = field().default_script.invokeOnDefault(ctx, value)
| field(). script.invokeOn(ctx, value); | field(). script.invokeOn(ctx, value);
+2
View File
@@ -78,6 +78,8 @@ public:
ValueType value; ///< The value ValueType value; ///< The value
bool isDefault() override;
bool update(Context&) override; bool update(Context&) override;
}; };
+4
View File
@@ -39,6 +39,10 @@ String ImageValue::toString() const {
return filename.empty() ? _("") : _("<image>"); return filename.empty() ? _("") : _("<image>");
} }
bool ImageValue::isDefault() {
return filename.empty();
}
// custom reflection: convert to ScriptImageP for scripting // custom reflection: convert to ScriptImageP for scripting
void ImageValue::reflect(Reader& handler) { void ImageValue::reflect(Reader& handler) {
+2
View File
@@ -48,6 +48,8 @@ public:
ValueType filename; ///< Filename of the image (in the current package), or "" ValueType filename; ///< Filename of the image (in the current package), or ""
Age last_update; ///< When was the image last changed? Age last_update; ///< When was the image last changed?
bool isDefault() override;
}; };
// ----------------------------------------------------------------------------- : ImageStyle // ----------------------------------------------------------------------------- : ImageStyle
+5
View File
@@ -63,6 +63,11 @@ IMPLEMENT_REFLECTION(InfoStyle) {
String InfoValue::toString() const { String InfoValue::toString() const {
return value; return value;
} }
bool InfoValue::isDefault() {
return true;
}
bool InfoValue::update(Context& ctx) { bool InfoValue::update(Context& ctx) {
if (value.empty()) value = field().caption.get(); if (value.empty()) value = field().caption.get();
bool change = field().script.invokeOn(ctx, value); bool change = field().script.invokeOn(ctx, value);
+2
View File
@@ -61,6 +61,8 @@ public:
ValueType value; ValueType value;
bool isDefault() override;
bool update(Context&) override; bool update(Context&) override;
}; };
+4
View File
@@ -52,6 +52,10 @@ IMPLEMENT_REFLECTION_NAMELESS(MultipleChoiceValue) {
REFLECT_BASE(ChoiceValue); REFLECT_BASE(ChoiceValue);
} }
bool MultipleChoiceValue::isDefault() {
return value.isDefault();
}
bool MultipleChoiceValue::update(Context& ctx) { bool MultipleChoiceValue::update(Context& ctx) {
String old_value = value(); String old_value = value();
ctx.setVariable(_("last_change"), to_script(last_change)); ctx.setVariable(_("last_change"), to_script(last_change));
+2
View File
@@ -64,6 +64,8 @@ public:
/// Splits the value, stores the selected choices in the out parameter /// Splits the value, stores the selected choices in the out parameter
void get(vector<String>& out) const; void get(vector<String>& out) const;
bool isDefault() override;
bool update(Context&) override; bool update(Context&) override;
private: private:
+6
View File
@@ -62,6 +62,12 @@ PackagedP PackageChoiceValue::getPackage() const {
else return package_manager.openAny(package_name, true); 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 PackageChoiceValue::update(Context& ctx) {
bool change = field().script.invokeOn(ctx, package_name); bool change = field().script.invokeOn(ctx, package_name);
Value::update(ctx); Value::update(ctx);
+2
View File
@@ -62,6 +62,8 @@ public:
/// Get the package (if it is set), otherwise return nullptr /// Get the package (if it is set), otherwise return nullptr
PackagedP getPackage() const; PackagedP getPackage() const;
bool isDefault() override;
bool update(Context&) override; bool update(Context&) override;
}; };
+4
View File
@@ -51,6 +51,10 @@ String SymbolValue::toString() const {
return filename.empty() ? _("") : _("<symbol>"); return filename.empty() ? _("") : _("<symbol>");
} }
bool SymbolValue::isDefault() {
return filename.empty();
}
IMPLEMENT_REFLECTION_NO_GET_MEMBER(SymbolValue) { IMPLEMENT_REFLECTION_NO_GET_MEMBER(SymbolValue) {
if (fieldP->save_value || !handler.isWriting) REFLECT_NAMELESS(filename); if (fieldP->save_value || !handler.isWriting) REFLECT_NAMELESS(filename);
} }
+2
View File
@@ -70,5 +70,7 @@ public:
ValueType filename; ///< Filename of the symbol (in the current package) ValueType filename; ///< Filename of the symbol (in the current package)
Age last_update; ///< When was the symbol last changed? Age last_update; ///< When was the symbol last changed?
bool isDefault() override;
}; };
+5
View File
@@ -177,6 +177,11 @@ IMPLEMENT_REFLECTION(TextStyle) {
String TextValue::toString() const { String TextValue::toString() const {
return untag_hide_sep(value()); return untag_hide_sep(value());
} }
bool TextValue::isDefault() {
return value.isDefault();
}
bool TextValue::update(Context& ctx) { bool TextValue::update(Context& ctx) {
updateAge(); updateAge();
WITH_DYNAMIC_ARG(last_update_age, last_update.get()); WITH_DYNAMIC_ARG(last_update_age, last_update.get());
+2
View File
@@ -113,6 +113,8 @@ public:
ValueType value; ///< The text of this value ValueType value; ///< The text of this value
Age last_update; ///< When was the text last changed? Age last_update; ///< When was the text last changed?
bool isDefault() override;
bool update(Context&) override; bool update(Context&) override;
}; };
+1 -1
View File
@@ -640,8 +640,8 @@ ApprenticeExportWindow::ApprenticeExportWindow(Window* parent, const SetP& set)
s->Add(new wxStaticText(this, -1, _HELP_( "set code")), 0, wxALL, 4); s->Add(new wxStaticText(this, -1, _HELP_( "set code")), 0, wxALL, 4);
s->AddSpacer(4); s->AddSpacer(4);
s->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | (wxALL & ~wxTOP), 8); s->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | (wxALL & ~wxTOP), 8);
s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
} }
void ApprenticeExportWindow::onApprenticeBrowse(wxCommandEvent& ev) { void ApprenticeExportWindow::onApprenticeBrowse(wxCommandEvent& ev) {
+45 -22
View File
@@ -63,7 +63,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) { CardsDataObject::CardsDataObject(const SetP& set, const String& id, const vector<CardP>& cards)
: wxCustomDataObject(format)
{
// set the stylesheet, so when deserializing we know whos style options we are reading // set the stylesheet, so when deserializing we know whos style options we are reading
vector<bool> has_styling; vector<bool> has_styling;
for (size_t i = 0 ; i < cards.size() ; ++i) { for (size_t i = 0 ; i < cards.size() ; ++i) {
@@ -72,9 +74,15 @@ CardsDataObject::CardsDataObject(const SetP& set, const String id, const vector<
cards[i]->stylesheet = set->stylesheet; cards[i]->stylesheet = set->stylesheet;
} }
} }
// store as raw bytes
WrappedCards data = { set->game.get(), set->game->name(), id, cards }; WrappedCards data = { set->game.get(), set->game->name(), id, cards };
SetText(serialize_for_clipboard(*set, data)); String serialized = serialize_for_clipboard(*set, data);
// restore cards wxScopedCharBuffer utf8 = serialized.utf8_str();
buffer.assign(utf8.data(), utf8.length());
SetData(buffer.size(), buffer.data());
// restore styling
for (size_t i = 0 ; i < cards.size() ; ++i) { for (size_t i = 0 ; i < cards.size() ; ++i) {
if (has_styling[i]) { if (has_styling[i]) {
cards[i]->stylesheet = StyleSheetP(); cards[i]->stylesheet = StyleSheetP();
@@ -83,22 +91,31 @@ CardsDataObject::CardsDataObject(const SetP& set, const String id, const vector<
SetFormat(format); SetFormat(format);
} }
CardsDataObject::CardsDataObject() { CardsDataObject::CardsDataObject()
SetFormat(format); : wxCustomDataObject(format)
} {}
bool CardsDataObject::getCards(const SetP& set, const String id, vector<CardP>& out) { 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));
WrappedCards data = { set->game.get(), set->game->name() }; WrappedCards data = { set->game.get(), set->game->name() };
deserialize_from_clipboard(data, *set, GetText()); try {
if (data.cards.empty()) return false; deserialize_from_clipboard(data, *set, text);
if (!id.empty() && data.id == id) return false; } catch (...) {
if (data.game_name == set->game->name()) { queue_message(MESSAGE_ERROR, _("DEBUG: Card deserialization failed"));
// Cards are from the same game
out = data.cards;
return true;
} else {
return false; return false;
} }
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;
} }
// ----------------------------------------------------------------------------- : KeywordDataObject // ----------------------------------------------------------------------------- : KeywordDataObject
@@ -144,23 +161,29 @@ KeywordP KeywordDataObject::getKeyword(const SetP& set) {
// ----------------------------------------------------------------------------- : Card on clipboard // ----------------------------------------------------------------------------- : Card on clipboard
CardsOnClipboard::CardsOnClipboard(const SetP& set, const String id, const vector<CardP>& cards) { CardsOnClipboard::CardsOnClipboard(const SetP& set, const String id, const vector<CardP>& cards) {
wxBusyCursor busy;
// Conversion to image file // Conversion to image file
if (cards.size() < 6) { if (cards.size() < 6) {
Bitmap bmp;
Image img; Image img;
if (cards.size() == 1) { if (cards.size() == 1) {
img = export_image(set, cards[0]); img = export_image(set, cards[0], true, 1.0, 0.0, 0.0, &bmp);
} }
else { else {
img = export_image(set, cards); img = export_image(set, cards);
bmp = Bitmap(img);
} }
String temp_path = wxFileName::CreateTempFileName(_("mse")) + _(".png"); //wxFileDataObject* fileData = new wxFileDataObject(); // needed for pasting on desktop, but slow
img.SaveFile(temp_path, wxBITMAP_TYPE_PNG); //String temp_path = wxFileName::CreateTempFileName(_("mse")) + _(".png");
wxFileDataObject* fileData = new wxFileDataObject(); //img.SaveFile(temp_path, wxBITMAP_TYPE_PNG);
fileData->AddFile(temp_path); //fileData->AddFile(temp_path);
Add(fileData); //Add(fileData);
wxImageDataObject* imgData = new wxImageDataObject(); wxImageDataObject* imgData = new wxImageDataObject(); // needed for metadata
imgData->SetImage(img); imgData->SetImage(img);
Add(imgData); Add(imgData);
wxBitmapDataObject* bmpData = new wxBitmapDataObject(); // needed for pasting in MSPaint
bmpData->SetBitmap(bmp);
Add(bmpData);
} }
// Conversion to serialized card format // Conversion to serialized card format
Add(new CardsDataObject(set, id, cards), true); Add(new CardsDataObject(set, id, cards), true);
+6 -3
View File
@@ -18,19 +18,22 @@ DECLARE_POINTER_TYPE(Keyword);
// ----------------------------------------------------------------------------- : CardDataObject // ----------------------------------------------------------------------------- : CardDataObject
/// The data format for cards on the clipboard /// The data format for cards on the clipboard
class CardsDataObject : public wxTextDataObject { class CardsDataObject : public wxCustomDataObject {
public: public:
/// Name of the format of MSE cards /// Name of the format of MSE cards
static wxDataFormat format; static wxDataFormat format;
CardsDataObject(); CardsDataObject();
/// Store a card /// 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 /// 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 /// 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 */ /** 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); bool getCards(const SetP& set, const String& id, vector<CardP>& out);
private:
std::string buffer; // keep data alive for wx
}; };
// ----------------------------------------------------------------------------- : KeywordDataObject // ----------------------------------------------------------------------------- : KeywordDataObject
+1 -1
View File
@@ -89,7 +89,7 @@ FileFormatP mtg_editor_file_format();
// ----------------------------------------------------------------------------- : Other ways to export // ----------------------------------------------------------------------------- : Other ways to export
/// Generate a wxImage of one or more cards /// 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); 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 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); 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 /// Export the image of one or more cards to a given filename, using the app's zoom, rotation and bleed settings, and including metadata
+5 -3
View File
@@ -35,7 +35,7 @@ Rotation ZoomedUnrotatedDataViewer::getRotation() const {
// ----------------------------------------------------------------------------- : wxImage export // ----------------------------------------------------------------------------- : wxImage export
Image export_image(const SetP& set, const CardP& card, bool write_metadata, double zoom, Radians angle_radians, double bleed_pixels) { Image export_image(const SetP& set, const CardP& card, bool write_metadata, double zoom, Radians angle_radians, double bleed_pixels, Bitmap* out_bitmap) {
if (!set) throw Error(_("no set")); if (!set) throw Error(_("no set"));
/// create and zoom /// create and zoom
ZoomedUnrotatedDataViewer viewer = ZoomedUnrotatedDataViewer(zoom); ZoomedUnrotatedDataViewer viewer = ZoomedUnrotatedDataViewer(zoom);
@@ -52,6 +52,9 @@ Image export_image(const SetP& set, const CardP& card, bool write_metadata, doub
dc.SelectObject(wxNullBitmap); dc.SelectObject(wxNullBitmap);
Image img = bitmap.ConvertToImage(); Image img = bitmap.ConvertToImage();
/// return bitmap if needed
if (out_bitmap) *out_bitmap = std::move(bitmap);
/// rotate /// rotate
img = rotate_image(img, angle_radians); img = rotate_image(img, angle_radians);
@@ -218,8 +221,7 @@ void export_image(const SetP& set, const CardP& card, const String& filename) {
img.SaveFile(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; wxBusyCursor busy;
// Script // Script
ScriptP filename_script = parse(filename_template, nullptr, true); ScriptP filename_script = parse(filename_template, nullptr, true);
+84 -80
View File
@@ -13,6 +13,7 @@
#include <boost/json.hpp> #include <boost/json.hpp>
#include <wx/filename.h> #include <wx/filename.h>
#include <fstream> #include <fstream>
#include <filesystem>
// ----------------------------------------------------------------------------- : Crop Rect Encoding // ----------------------------------------------------------------------------- : Crop Rect Encoding
@@ -36,44 +37,44 @@ inline static String encodeRectInWxString(RealRect rect, int degrees) {
_("</mse-crop-data>"); _("</mse-crop-data>");
} }
/// Retreive a rect encoded in a string, return true if successful /// Retreive a rect encoded in a string, return true if "<mse-crop-data>" was found
inline static bool decodeRectFromString(const String& rectString, RealRect& rect_out, int& degrees_out) { inline static bool decodeRectFromString(const String& rectString, RealRect& rect_out, int& degrees_out) {
size_t start = rectString.find(_("<mse-crop-data>")); size_t start = rectString.find(_("<mse-crop-data>"));
if (start == String::npos) return false; if (start == String::npos) return false;
size_t end = rectString.find(_("</mse-crop-data>"), start + 15); size_t end = rectString.find(_("</mse-crop-data>"), start + 15);
if (end == String::npos) return false; if (end == String::npos) return true;
String string = rectString.substr(start + 15, end - (start + 15)); String string = rectString.substr(start + 15, end - (start + 15));
if (string.empty()) return false; if (string.empty()) return true;
size_t divider = string.find(_(";")); size_t divider = string.find(_(";"));
if (divider == String::npos) return false; if (divider == String::npos) return true;
if (divider == 0) return false; if (divider == 0) return true;
int x; int x;
if(!string.substr(0, divider).ToInt(&x)) return false; if(!string.substr(0, divider).ToInt(&x)) return true;
string = string.substr(divider + 1); string = string.substr(divider + 1);
divider = string.find(_(";")); divider = string.find(_(";"));
if (divider == String::npos) return false; if (divider == String::npos) return true;
if (divider == 0) return false; if (divider == 0) return true;
int y; int y;
if(!string.substr(0, divider).ToInt(&y)) return false; if(!string.substr(0, divider).ToInt(&y)) return true;
string = string.substr(divider + 1); string = string.substr(divider + 1);
divider = string.find(_(";")); divider = string.find(_(";"));
if (divider == String::npos) return false; if (divider == String::npos) return true;
if (divider == 0) return false; if (divider == 0) return true;
int width; int width;
if(!string.substr(0, divider).ToInt(&width)) return false; if(!string.substr(0, divider).ToInt(&width)) return true;
string = string.substr(divider + 1); string = string.substr(divider + 1);
divider = string.find(_(";")); divider = string.find(_(";"));
if (divider == String::npos) return false; if (divider == String::npos) return true;
if (divider == 0) return false; if (divider == 0) return true;
int height; int height;
if(!string.substr(0, divider).ToInt(&height)) return false; if(!string.substr(0, divider).ToInt(&height)) return true;
string = string.substr(divider + 1); string = string.substr(divider + 1);
if(!string.ToInt(&degrees_out)) return false; if(!string.ToInt(&degrees_out)) return true;
rect_out = RealRect(x, y, width, height); rect_out = RealRect(x, y, width, height);
return true; return true;
@@ -81,17 +82,18 @@ inline static bool decodeRectFromString(const String& rectString, RealRect& rect
/// Retreive a rect encoded in a string, apply a transformation, then encode it back /// 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) { inline static String transformEncodedRect(const String& rectString, RectTransform transform, double param_x, double param_y, int mode) {
RealRect rect(0,0,0,0); RealRect rect(0.0, 0.0, 0.0, 0.0);
int degrees; int degrees = 0;
if (!decodeRectFromString(rectString, rect, degrees)) return _(""); decodeRectFromString(rectString, rect, degrees);
transform(rect, degrees, param_x, param_y, mode); if (rect.width > 0.0 && rect.height > 0.0) {
return encodeRectInWxString(rect, degrees); transform(rect, degrees, param_x, param_y, mode);
return encodeRectInWxString(rect, degrees);
}
return _("");
} }
/// Retreive all rects encoded in a string, apply a transformation, then encode them back /// 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) { 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>")); size_t start = rectString.find(_("<mse-crop-data>"));
if (start == String::npos) return rectString; if (start == String::npos) return rectString;
size_t end = 0; size_t end = 0;
@@ -110,67 +112,70 @@ inline static String transformAllEncodedRects(const String& rectString, RectTran
// ----------------------------------------------------------------------------- : File to UTF8 Encoding // ----------------------------------------------------------------------------- : 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 /// Encode a file in a string
inline static std::string fileToUTF8(const std::string& filepath) { inline static std::string fileToUTF8(const std::string& filepath) {
// File to char // Load file
std::ifstream file(filepath, std::ios::binary); std::ifstream file(filepath, std::ios::binary);
file.unsetf(std::ios::skipws); if (!file) {
std::vector<unsigned char> buffer = std::vector<unsigned char>(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()); queue_message(MESSAGE_WARNING, _("Could not find file: ") + String(filepath));
int size = buffer.size();
if (size < 2) {
queue_message(MESSAGE_WARNING, _("File too small to encode"));
return ""; return "";
} }
// All bytes that have a highest bit of 0 are valid UTF8 characters, so: size_t size = std::filesystem::file_size(filepath);
// Reset the highest bit of each byte, store these bits in additional bytes at the end std::vector<uint8_t> data(size);
const unsigned char highest_bit = 1 << 7; file.read(reinterpret_cast<char*>(data.data()), size);
unsigned char added_byte = 0; // Base64 encode
for (int i = 0, b = 0 ; i < size ; ++i, ++b) { std::string out;
if (b == 7) { // Never set the highest bit of the added byte out.reserve(((size + 2) / 3) * 4);
buffer.push_back(added_byte); int val = 0;
b = 0; int valb = -6;
} for (uint8_t c : data) {
unsigned char bit = 1 << b; val = (val << 8) | c;
if ((buffer[i] & highest_bit) != 0) { // The highest bit of the buffer is set valb += 8;
buffer[i] &= ~highest_bit; // Reset the highest bit of the buffer while (valb >= 0) {
added_byte |= bit; // Set the bit of the added byte out.push_back(Base64Alphabet[(val >> valb) & 0x3F]);
} else { valb -= 6;
added_byte &= ~bit; // Reset the bit of the added byte
} }
} }
buffer.push_back(added_byte); if (valb > -6) {
// Char to string out.push_back(Base64Alphabet[((val << 8) >> (valb + 8)) & 0x3F]);
return std::string(buffer.begin(), buffer.end()); }
// Pad
while (out.size() % 4) {
out.push_back('=');
}
return out;
} }
/// Retreive a file encoded in a string, return true if successful /// Retreive a file encoded in a string, return true if successful
inline static bool UTF8ToFile(const std::string& filepath, std::string& string) { inline static bool UTF8ToFile(const std::string& filepath, std::string& data) {
// String to char // Base64 decode
std::vector<unsigned char> buffer(string.begin(), string.end()); std::string out;
int size = buffer.size(); out.reserve(data.size() * 3 / 4);
if (size < 2) { int val = 0;
queue_message(MESSAGE_WARNING, _("File too small to decode")); int valb = -8;
return false; for (uint8_t c : data) {
} if (c == '=') break; // padding, we're done
// Restore the highest bit of each byte val = (val << 6) | Base64ReverseAlphabet[c];
size = (size * 7) / 8; valb += 6;
const unsigned char highest_bit = 1 << 7; if (valb >= 0) {
unsigned char added_byte = buffer[size]; out.push_back(static_cast<char>((val >> valb) & 0xFF));
for (int i = 0, j = size, b = 0 ; i < size ; ++i, ++b) { valb -= 8;
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
} }
} }
buffer.resize(size); // Save file
// Char to file std::ofstream file(filepath, std::ios::binary);
std::ofstream file(filepath, std::ios::out|std::ios::binary); file.write(out.data(), out.size());
std::copy(buffer.cbegin(), buffer.cend(), std::ostream_iterator<unsigned char>(file));
return true; return true;
} }
@@ -184,22 +189,21 @@ inline static std::string encodeImageInString(const Image& img) {
return s; return s;
} }
/// Retreive an image encoded in a string /// Retreive an image encoded in a string, return true if "<mse-image-data>" was found
inline static Image decodeImageFromString(const String& string) { inline static bool decodeImageFromString(const String& string, Image& img_out) {
Image img;
size_t first = string.find(_("<mse-image-data>")); size_t first = string.find(_("<mse-image-data>"));
if (first == String::npos) return img; if (first == String::npos) return false;
size_t last = string.find(_("</mse-image-data>"), first + 16); size_t last = string.find(_("</mse-image-data>"), first + 16);
if (last == String::npos) return img; if (last == String::npos) return true;
std::string s = string.substr(first + 16, last - (first + 16)).ToStdString(); std::string s = string.substr(first + 16, last - (first + 16)).ToStdString();
if (s.empty()) return img; if (s.empty()) return true;
const std::string& temppath = (wxFileName::CreateTempFileName(_("mse")) + _(".png")).ToStdString(); const std::string& temppath = (wxFileName::CreateTempFileName(_("mse")) + _(".png")).ToStdString();
UTF8ToFile(temppath, s); UTF8ToFile(temppath, s);
img.LoadFile(temppath, wxBITMAP_TYPE_PNG); img_out.LoadFile(temppath, wxBITMAP_TYPE_PNG);
wxRemoveFile(temppath); wxRemoveFile(temppath);
wxRemoveFile(temppath.substr(0, temppath.size() - 4)); wxRemoveFile(temppath.substr(0, temppath.size() - 4));
return img; return true;
} }
// ----------------------------------------------------------------------------- : Metadata manipulation // ----------------------------------------------------------------------------- : Metadata manipulation
+6 -1
View File
@@ -16,6 +16,7 @@
#include <data/pack.hpp> #include <data/pack.hpp>
#include <data/word_list.hpp> #include <data/word_list.hpp>
#include <data/add_cards_script.hpp> #include <data/add_cards_script.hpp>
#include <data/update_cards_script.hpp>
#include <util/io/package_manager.hpp> #include <util/io/package_manager.hpp>
#include <script/script.hpp> #include <script/script.hpp>
@@ -55,7 +56,6 @@ IMPLEMENT_REFLECTION(Game) {
REFLECT_NO_SCRIPT(json_paths); REFLECT_NO_SCRIPT(json_paths);
REFLECT_NO_SCRIPT(statistics_dimensions); REFLECT_NO_SCRIPT(statistics_dimensions);
REFLECT_NO_SCRIPT(statistics_categories); REFLECT_NO_SCRIPT(statistics_categories);
REFLECT_COMPAT(<308, "pack_item", pack_types);
REFLECT_NO_SCRIPT(pack_types); REFLECT_NO_SCRIPT(pack_types);
REFLECT_NO_SCRIPT(keyword_match_script); REFLECT_NO_SCRIPT(keyword_match_script);
REFLECT(has_keywords); REFLECT(has_keywords);
@@ -64,6 +64,7 @@ IMPLEMENT_REFLECTION(Game) {
REFLECT_NO_SCRIPT(keywords); REFLECT_NO_SCRIPT(keywords);
REFLECT_NO_SCRIPT(word_lists); REFLECT_NO_SCRIPT(word_lists);
REFLECT_NO_SCRIPT(add_cards_scripts); REFLECT_NO_SCRIPT(add_cards_scripts);
REFLECT_NO_SCRIPT(update_cards_scripts);
REFLECT_NO_SCRIPT(auto_replaces); REFLECT_NO_SCRIPT(auto_replaces);
} }
@@ -206,6 +207,10 @@ void Game::validate(Version v) {
card_links_alt_names.emplace(linked_tr, linked_default); 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() { void Game::initCardListColorScript() {
+23 -21
View File
@@ -26,6 +26,7 @@ DECLARE_POINTER_TYPE(KeywordMode);
DECLARE_POINTER_TYPE(Keyword); DECLARE_POINTER_TYPE(Keyword);
DECLARE_POINTER_TYPE(WordList); DECLARE_POINTER_TYPE(WordList);
DECLARE_POINTER_TYPE(AddCardsScript); DECLARE_POINTER_TYPE(AddCardsScript);
DECLARE_POINTER_TYPE(UpdateCardsScript);
DECLARE_POINTER_TYPE(AutoReplace); DECLARE_POINTER_TYPE(AutoReplace);
// ----------------------------------------------------------------------------- : Game // ----------------------------------------------------------------------------- : Game
@@ -38,27 +39,28 @@ class Game : public Packaged {
public: public:
Game(); Game();
OptionalScript init_script; ///< Script of variables available to other scripts in this game OptionalScript init_script; ///< Script of variables available to other scripts in this game
vector<FieldP> set_fields; ///< Fields for set information 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 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<FieldP> card_fields; ///< Fields on each card
vector<CardLinkP> card_links; ///< Possible links between cards 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 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 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<String> json_paths; ///< Paths inside JSON files to find the card array
vector<StatsDimensionP> statistics_dimensions; ///< (Additional) statistics dimensions vector<StatsDimensionP> statistics_dimensions; ///< (Additional) statistics dimensions
vector<StatsCategoryP> statistics_categories; ///< (Additional) statistics categories vector<StatsCategoryP> statistics_categories; ///< (Additional) statistics categories
vector<PackTypeP> pack_types; ///< Types of random card packs to generate 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<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<AddCardsScriptP> add_cards_scripts; ///< Scripts for adding multiple cards to the set
vector<AutoReplaceP> auto_replaces; ///< Things to autoreplace in textboxes vector<UpdateCardsScriptP> update_cards_scripts; ///< Scripts for updating cards made with an earlier version of this game
map<String,String> card_fields_alt_names; ///< Other names that fields might go by, for example in CSV files vector<AutoReplaceP> auto_replaces; ///< Things to autoreplace in textboxes
map<String,String> card_links_alt_names; ///< Localized names that card links go by map<String,String> card_fields_alt_names; ///< Other names that fields might go by, for example in CSV files
bool has_keywords; ///< Does this game use keywords? map<String,String> card_links_alt_names; ///< Localized names that card links go by
OptionalScript keyword_match_script; ///< For the keyword editor bool has_keywords; ///< Does this game use keywords?
vector<KeywordParamP> keyword_parameter_types;///< Types of keyword parameters OptionalScript keyword_match_script; ///< For the keyword editor
vector<KeywordModeP> keyword_modes; ///< Modes of keywords vector<KeywordParamP> keyword_parameter_types;///< Types of keyword parameters
vector<KeywordP> keywords; ///< Keywords for use in text 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_cards; ///< scripts that depend on the card list
Dependencies dependent_scripts_keywords; ///< scripts that depend on the keywords Dependencies dependent_scripts_keywords; ///< scripts that depend on the keywords
+22
View File
@@ -16,6 +16,7 @@
#include <util/io/package_manager.hpp> #include <util/io/package_manager.hpp>
#include <util/platform.hpp> #include <util/platform.hpp>
#include <gui/util.hpp> // load_resource_image #include <gui/util.hpp> // load_resource_image
#include <wx/webrequest.h>
#include <wx/filename.h> #include <wx/filename.h>
#include <wx/wfstream.h> #include <wx/wfstream.h>
#include <wx/zipstrm.h> #include <wx/zipstrm.h>
@@ -319,6 +320,27 @@ void InstallablePackage::determineStatus() {
} }
} }
bool InstallablePackage::ensureIsDownloaded() {
if (!installer) return true; // Nothing to download
if (installer->installer) return true; // Already loaded
if (installer->installer_url.empty()) return false; // No URL
// download installer
wxWebRequestSync request = wxWebSessionSync::GetDefault().CreateRequest(installer->installer_url);
auto const result = request.Execute();
if (!result) {
throw Error(_ERROR_2_("can't download installer", description->name, installer->installer_url));
}
wxInputStream* is(request.GetResponse().GetStream());
installer->installer_file = wxFileName::CreateTempFileName(_("mse-installer"));
wxFileOutputStream os(installer->installer_file);
os.Write(*is);
os.Close();
// open installer
installer->installer = make_intrusive<Installer>();
installer->installer->open(installer->installer_file);
return true;
}
bool InstallablePackage::willBeInstalled() const { bool InstallablePackage::willBeInstalled() const {
return has(PACKAGE_ACT_INSTALL) || return has(PACKAGE_ACT_INSTALL) ||
(has(PACKAGE_INSTALLED) && !has(PACKAGE_ACT_REMOVE)); (has(PACKAGE_INSTALLED) && !has(PACKAGE_ACT_REMOVE));
+1
View File
@@ -152,6 +152,7 @@ public:
int old_automatic; int old_automatic;
void determineStatus(); void determineStatus();
bool ensureIsDownloaded();
/// After the action, will the package be installed? /// After the action, will the package be installed?
bool willBeInstalled() const; bool willBeInstalled() const;
-1
View File
@@ -85,7 +85,6 @@ bool Keyword::contains(QuickFilterPart const& query) const {
IMPLEMENT_REFLECTION(Keyword) { IMPLEMENT_REFLECTION(Keyword) {
REFLECT(keyword); REFLECT(keyword);
if (handler.formatVersion() < 301) read_compat(handler, this);
REFLECT(match); REFLECT(match);
REFLECT(reminder); REFLECT(reminder);
REFLECT(rules); REFLECT(rules);
+80 -7
View File
@@ -14,6 +14,7 @@
#include <data/keyword.hpp> #include <data/keyword.hpp>
#include <data/pack.hpp> #include <data/pack.hpp>
#include <data/field.hpp> #include <data/field.hpp>
#include <data/update_cards_script.hpp>
#include <data/field/text.hpp> // for 0.2.7 fix #include <data/field/text.hpp> // for 0.2.7 fix
#include <data/field/information.hpp> #include <data/field/information.hpp>
#include <data/field/image.hpp> #include <data/field/image.hpp>
@@ -22,6 +23,7 @@
#include <util/tagged_string.hpp> // for 0.2.7 fix #include <util/tagged_string.hpp> // for 0.2.7 fix
#include <util/order_cache.hpp> #include <util/order_cache.hpp>
#include <util/delayed_index_maps.hpp> #include <util/delayed_index_maps.hpp>
#include <util/uid.hpp>
#include <script/script_manager.hpp> #include <script/script_manager.hpp>
#include <script/profiler.hpp> #include <script/profiler.hpp>
#include <wx/sstream.h> #include <wx/sstream.h>
@@ -67,6 +69,16 @@ void Set::updateStyles(const CardP& card, bool only_content_dependent) {
void Set::updateDelayed() { void Set::updateDelayed() {
script_manager->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() { Context& Set::getContextForThumbnails() {
assert(!wxThread::IsMain()); assert(!wxThread::IsMain());
@@ -161,7 +173,7 @@ void fix_value_207(const ValueP& value) {
void Set::validate(Version file_app_version) { void Set::validate(Version file_app_version) {
Packaged::validate(file_app_version); Packaged::validate(file_app_version);
// are the // are the game and stylesheet defined?
if (!game) { if (!game) {
throw Error(_ERROR_1_("no game specified",_TYPE_("set"))); throw Error(_ERROR_1_("no game specified",_TYPE_("set")));
} }
@@ -173,6 +185,8 @@ void Set::validate(Version file_app_version) {
throw Error(_ERROR_("stylesheet and set refer to different game")); throw Error(_ERROR_("stylesheet and set refer to different game"));
} }
// We can probably retire this
/*
// This is our chance to fix version incompatabilities // This is our chance to fix version incompatabilities
if (file_app_version < 207) { if (file_app_version < 207) {
// Since 0.2.7 we use </tag> style close tags, in older versions it was </> // Since 0.2.7 we use </tag> style close tags, in older versions it was </>
@@ -181,14 +195,65 @@ void Set::validate(Version file_app_version) {
FOR_EACH(v, c->data) fix_value_207(v); FOR_EACH(v, c->data) fix_value_207(v);
} }
FOR_EACH(v, 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); FOR_EACH(v, s.second->data) fix_value_207(v);
} }
*/ } }
*/
// we want at least one card // we want at least one card
if (cards.empty()) cards.push_back(make_intrusive<Card>(*game)); if (cards.empty()) cards.push_back(make_intrusive<Card>(*game));
// build uid map
buildUIDMap();
// update scripts // update scripts
script_manager->updateAll(); script_manager->updateAll();
// 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;
}
}
}
} }
void reflect_version_check(Reader& handler, const Char* key, intrusive_ptr<Packaged> const& package) { void reflect_version_check(Reader& handler, const Char* key, intrusive_ptr<Packaged> const& package) {
@@ -212,15 +277,23 @@ IMPLEMENT_REFLECTION(Set) {
REFLECT_IF_READING { REFLECT_IF_READING {
data.init(game->set_fields); data.init(game->set_fields);
} }
reflect_version_check(handler, _("game_version"), game); if (Handler::isReading) {
REFLECT_NO_SCRIPT(game_version);
}
else {
reflect_version_check(handler, _("game_version"), game);
}
WITH_DYNAMIC_ARG(game_for_reading, game.get()); WITH_DYNAMIC_ARG(game_for_reading, game.get());
REFLECT(stylesheet); REFLECT(stylesheet);
REFLECT_COMPAT(<300, "style", stylesheet); if (Handler::isReading) {
reflect_version_check(handler, _("stylesheet_version"), stylesheet); REFLECT_NO_SCRIPT(stylesheet_version);
}
else {
reflect_version_check(handler, _("stylesheet_version"), stylesheet);
}
WITH_DYNAMIC_ARG(stylesheet_for_reading, stylesheet.get()); WITH_DYNAMIC_ARG(stylesheet_for_reading, stylesheet.get());
REFLECT_N("set_info", data); REFLECT_N("set_info", data);
if (stylesheet) { if (stylesheet) {
REFLECT_COMPAT(<300, "extra_set_info", styling_data);
REFLECT_N("styling", styling_data); REFLECT_N("styling", styling_data);
} }
// Experimental: save each card to a different file // Experimental: save each card to a different file
+17 -10
View File
@@ -45,21 +45,26 @@ public:
Set(const StyleSheetP& stylesheet); Set(const StyleSheetP& stylesheet);
~Set(); ~Set();
GameP game; ///< The game this set uses GameP game; ///< The game this set uses
StyleSheetP stylesheet; ///< The default stylesheet StyleSheetP stylesheet; ///< The default stylesheet
/// The values on the fields of the set /// The values on the fields of the set
/** The indices should correspond to the set_fields in the Game */ /** 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 /// Extra values for specific stylesheets, indexed by stylesheet name
DelayedIndexMaps<FieldP,ValueP> styling_data; DelayedIndexMaps<FieldP,ValueP> styling_data;
vector<CardP> cards; ///< The cards in the set vector<CardP> cards; ///< The cards in the set
vector<KeywordP> keywords; ///< Additional keywords used in this set unordered_map<String, CardP> card_uids; ///< The uids of the cards in the set
vector<PackTypeP> pack_types; ///< Additional/replacement pack types vector<KeywordP> keywords; ///< Additional keywords used in this set
String apprentice_code; ///< Code to use for apprentice (magic only) 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 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 KeywordDatabase keyword_db; ///< Database for matching keywords, must be cleared when keywords change
VCSP vcs; ///< The version control system to use 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;
/// A context for performing scripts /// A context for performing scripts
/** Should only be used from the main thread! */ /** Should only be used from the main thread! */
@@ -71,6 +76,8 @@ public:
void updateStyles(const CardP& card, bool only_content_dependent); void updateStyles(const CardP& card, bool only_content_dependent);
/// Update scripts that were delayed /// Update scripts that were delayed
void updateDelayed(); void updateDelayed();
/// Update uid map
void buildUIDMap();
/// A context for performing scripts /// A context for performing scripts
/** Should only be used from the thumbnail thread! */ /** Should only be used from the thumbnail thread! */
Context& getContextForThumbnails(); Context& getContextForThumbnails();
+9 -11
View File
@@ -10,6 +10,7 @@
#include <data/stylesheet.hpp> #include <data/stylesheet.hpp>
#include <data/game.hpp> #include <data/game.hpp>
#include <data/field.hpp> #include <data/field.hpp>
#include <data/update_cards_script.hpp>
#include <util/io/package_manager.hpp> #include <util/io/package_manager.hpp>
#include <gui/new_window.hpp> // for selecting stylesheets on load error #include <gui/new_window.hpp> // for selecting stylesheets on load error
@@ -37,21 +38,13 @@ StyleSheetP StyleSheet::byGameAndName(const Game& game, const String& name) {
return package_manager.open<StyleSheet>(full_name); return package_manager.open<StyleSheet>(full_name);
} }
} catch (PackageNotFoundError& e) { } catch (PackageNotFoundError& e) {
queue_message(MESSAGE_ERROR, _("Missing stylesheet: ") + full_name);
// This causes a freeze when the set contains two cards that use the same missing StyleSheet, and the second one has styling_data
// Also, it's probably better to ask the user for an alternative for each missing StyleSheet individually
//if (stylesheet_for_reading()) {
// // we already have a stylesheet higher up, so just return a null pointer
// return StyleSheetP();
//}
// load an alternative stylesheet // load an alternative stylesheet
StyleSheetP ss = select_stylesheet(game, name); StyleSheetP ss = select_stylesheet(game, full_name);
if (ss) { if (ss) {
stylesheet_alternatives[full_name] = ss->relativeFilename(); stylesheet_alternatives[full_name] = ss->relativeFilename();
return ss; return ss;
} else { } else {
queue_message(MESSAGE_ERROR, _("Missing stylesheet: ") + full_name);
throw e; throw e;
} }
} }
@@ -76,6 +69,10 @@ void StyleSheet::validate(Version ver) {
} }
// a stylesheet depends on the game it is made for // a stylesheet depends on the game it is made for
requireDependency(game.get()); 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;
});
} }
@@ -98,8 +95,8 @@ void mark_dependency_value(const StyleSheet& stylesheet, const Dependency& dep)
IMPLEMENT_REFLECTION(StyleSheet) { IMPLEMENT_REFLECTION(StyleSheet) {
REFLECT(game);
REFLECT_BASE(Packaged); REFLECT_BASE(Packaged);
REFLECT(game);
REFLECT(card_width); REFLECT(card_width);
REFLECT(card_height); REFLECT(card_height);
REFLECT(card_dpi); REFLECT(card_dpi);
@@ -125,6 +122,7 @@ IMPLEMENT_REFLECTION(StyleSheet) {
extra_card_style.init(extra_card_fields); extra_card_style.init(extra_card_fields);
} }
REFLECT(extra_card_style); REFLECT(extra_card_style);
REFLECT_NO_SCRIPT(update_cards_scripts);
} }
+8 -6
View File
@@ -22,6 +22,7 @@ DECLARE_POINTER_TYPE(StyleSheet);
DECLARE_POINTER_TYPE(Field); DECLARE_POINTER_TYPE(Field);
DECLARE_POINTER_TYPE(Style); DECLARE_POINTER_TYPE(Style);
DECLARE_POINTER_TYPE(CardRegion); DECLARE_POINTER_TYPE(CardRegion);
DECLARE_POINTER_TYPE(UpdateCardsScript);
// ----------------------------------------------------------------------------- : StyleSheet // ----------------------------------------------------------------------------- : StyleSheet
@@ -33,12 +34,13 @@ class StyleSheet : public Packaged {
public: public:
StyleSheet(); StyleSheet();
GameP game; ///< The game this stylesheet is made for GameP game; ///< The game this stylesheet is made for
OptionalScript init_script; ///< Script of variables available to other scripts in this stylesheet OptionalScript init_script; ///< Script of variables available to other scripts in this stylesheet
double card_width; ///< The width of a card in pixels vector<UpdateCardsScriptP> update_cards_scripts; ///< Scripts for updating cards made with an earlier version of this stylesheet
double card_height; ///< The height of a card in pixels double card_width; ///< The width of a card in pixels
double card_dpi; ///< The resolution of a card in dots per inch double card_height; ///< The height of a card in pixels
Color card_background; ///< The background color of cards double card_dpi; ///< The resolution of a card in dots per inch
Color card_background; ///< The background color of cards
vector<CardRegionP> card_regions; vector<CardRegionP> card_regions;
/// The styling for card fields /// The styling for card fields
/** The indices should correspond to the card_fields in the Game */ /** The indices should correspond to the card_fields in the Game */
-1
View File
@@ -178,7 +178,6 @@ IMPLEMENT_REFLECTION(SymbolInFont) {
REFLECT(draw_text); REFLECT(draw_text);
REFLECT(text_font); REFLECT(text_font);
REFLECT(text_alignment); REFLECT(text_alignment);
REFLECT_COMPAT(<300,"text_align",text_alignment);
REFLECT(text_margin_left); REFLECT(text_margin_left);
REFLECT(text_margin_right); REFLECT(text_margin_right);
REFLECT(text_margin_top); REFLECT(text_margin_top);
+57
View File
@@ -0,0 +1,57 @@
//+----------------------------------------------------------------------------+
//| 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
@@ -0,0 +1,39 @@
//+----------------------------------------------------------------------------+
//| 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();
};
+32 -16
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) { void linear_blend(Image& img1, const Image& img2, double x1,double y1, double x2,double y2) {
int width = img1.GetWidth(), height = img1.GetHeight(); int width = img1.GetWidth(), height = img1.GetHeight();
if (img2.GetWidth() != width || img2.GetHeight() != height) { if (img2.GetWidth() != width || img2.GetHeight() != height) {
throw Error(_ERROR_1_("blending different sizes", "linear_blend")); throw Error(_ERROR_3_("blending different sizes", "linear_blend", String()<<width<<_("x")<<height, String()<<img2.GetWidth()<<_("x")<<img2.GetHeight()));
} }
const int fixed = 1<<16; // fixed point multiplier 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) { void mask_blend(Image& img1, const Image& img2, const Image& mask) {
int width = img1.GetWidth(), height = img1.GetHeight(); int width = img1.GetWidth(), height = img1.GetHeight();
if (img2.GetWidth() != width || img2.GetHeight() != height) { if (img2.GetWidth() != width || img2.GetHeight() != height) {
throw Error(_("Images used for blending in masked_blend function must have the same size")); throw Error(_ERROR_3_("blending different sizes", "masked_blend", String()<<width<<_("x")<<height, String()<<img2.GetWidth()<<_("x")<<img2.GetHeight()));
} }
if (mask.GetWidth() != width || mask.GetHeight() != height) { if (mask.GetWidth() != width || mask.GetHeight() != height) {
throw Error(_("Mask used for blending in masked_blend function must have the same size as the images")); throw Error(_ERROR_3_("blending different mask", "masked_blend", String()<<width<<_("x")<<height, String()<<mask.GetWidth()<<_("x")<<mask.GetHeight()));
} }
UInt size = width * height; UInt size = width * height;
@@ -124,17 +124,18 @@ void set_alpha(Image& img, const Image& img_alpha) {
} }
void set_alpha(Image& img, Byte* al, const wxSize& alpha_size) { void set_alpha(Image& img, Byte* al, const wxSize& alpha_size) {
if (img.GetWidth() != alpha_size.GetWidth() || img.GetHeight() != alpha_size.GetHeight()) { int width = img.GetWidth(), height = img.GetHeight();
throw Error(_("Image must have same size as mask")); 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.HasAlpha()) { if (!img.HasAlpha()) {
// copy // copy
img.InitAlpha(); img.InitAlpha();
memcpy(img.GetAlpha(), al, img.GetWidth() * img.GetHeight()); memcpy(img.GetAlpha(), al, width * height);
} else{ } else{
// merge // merge
Byte *im = img.GetAlpha(); Byte *im = img.GetAlpha();
size_t size = img.GetWidth() * img.GetHeight(); size_t size = width * height;
for (size_t i = 0 ; i < size ; ++i) { for (size_t i = 0 ; i < size ; ++i) {
im[i] = (im[i] * al[i]) / 255; im[i] = (im[i] * al[i]) / 255;
} }
@@ -142,15 +143,30 @@ void set_alpha(Image& img, Byte* al, const wxSize& alpha_size) {
} }
void set_alpha(Image& img, double alpha) { void set_alpha(Image& img, double alpha) {
Byte b_alpha = Byte(alpha * 255); size_t size = img.GetWidth() * img.GetHeight();
if (!img.HasAlpha()) { if (alpha <= 0.0) {
img.InitAlpha(); if (!img.HasAlpha()) img.InitAlpha();
memset(img.GetAlpha(), b_alpha, img.GetWidth() * img.GetHeight()); memset(img.GetAlpha(), Byte(0), size);
} else { }
Byte *im = img.GetAlpha(); else if (alpha > 1.0) {
size_t size = img.GetWidth() * img.GetHeight(); if (!img.HasAlpha()) return;
for (size_t i = 0 ; i < size ; ++i) { else {
im[i] = (im[i] * b_alpha) / 255; 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;
}
} }
} }
} }
+4 -3
View File
@@ -449,13 +449,14 @@ void combine_image_do(Image& a, Image b) {
void combine_image(Image& a, const Image& b, ImageCombine combine) { void combine_image(Image& a, const Image& b, ImageCombine combine) {
// Images must have same size // Images must have same size
if (a.GetWidth() != b.GetWidth() || a.GetHeight() != b.GetHeight()) { int width = a.GetWidth(), height = a.GetHeight();
throw Error(_ERROR_1_("blending different sizes", "combine_blend")); 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()));
} }
// Copy alpha channel? // Copy alpha channel?
if (b.HasAlpha()) { if (b.HasAlpha()) {
if (!a.HasAlpha()) a.InitAlpha(); if (!a.HasAlpha()) a.InitAlpha();
memcpy(a.GetAlpha(), b.GetAlpha(), a.GetWidth() * a.GetHeight()); memcpy(a.GetAlpha(), b.GetAlpha(), width * height);
} }
// Combine image data, by dispatching to combineImageDo // Combine image data, by dispatching to combineImageDo
switch(combine) { switch(combine) {
+54 -34
View File
@@ -783,32 +783,57 @@ bool SetMetadataImage::operator == (const GeneratedImage& that) const {
&& metadata == that2->metadata; && 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::ImportedImage(Set* set, const String& filepath) ImportedImage::ImportedImage(Set* set, const String& filepath) {
{ // determine save name
loadpath = filepath; loadpath = filepath;
savename = normalize_internal_filename(loadpath);
// has the set already been saved at least once? savename.Replace(_(":"), _("-"));
if (set->needSaveAs()) throw ScriptError(_ERROR_1_("can't import image without set", loadpath)); savename.Replace(_("/"), _("-"));
// does the file pointed to by filepath exist? // does the file pointed to by filepath exist?
if (!wxFileName(loadpath, wxPATH_UNIX).FileExists()) throw ScriptError(_ERROR_1_("import not found", loadpath)); if (!wxFileName(loadpath, wxPATH_UNIX).FileExists()) {
if (set->contains(savename)) return;
else throw ScriptError(_ERROR_1_("import not found", loadpath));
}
// is the file an image? // is the file an image?
Image img; Image img;
img.LoadFile(loadpath); img.LoadFile(loadpath);
if (!img.IsOk()) throw ScriptError(_ERROR_1_("import not image", loadpath)); if (!img.IsOk()) throw ScriptError(_ERROR_1_("import not image", loadpath));
// add the file to the set (or overwrite it if pre-existing), save set // add the file to the set
savename = normalize_internal_filename(loadpath + _(".png")); LocalFileName new_image_file = set->newFileName(savename, _(".png"));
savename.Replace(":", "-"); savename = new_image_file.toStringForWriting();
savename.Replace("/", "-"); img.SaveFile(set->nameOut(new_image_file), wxBITMAP_TYPE_PNG);
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) { Image ImportedImage::generate(const Options& opt) {
@@ -827,32 +852,27 @@ bool ImportedImage::operator == (const GeneratedImage& that) const {
// ----------------------------------------------------------------------------- : DownloadedImage // ----------------------------------------------------------------------------- : DownloadedImage
DownloadedImage::DownloadedImage(Set* set, const String& url) DownloadedImage::DownloadedImage(Set* set, const String& url) {
{ // determine save name
loadpath = url; loadpath = url;
savename = normalize_internal_filename(loadpath);
// has the set already been saved at least once? savename.Replace(":", "-");
if (set->needSaveAs()) throw ScriptError(_ERROR_1_("can't download image without set", loadpath)); savename.Replace("/", "-");
// can we download the data? // can we download the data?
WebRequestWindow wnd(loadpath); WebRequestWindow wnd(loadpath);
if (wnd.ShowModal() != wxID_OK) throw ScriptError(_ERROR_1_("can't download image", loadpath)); if (wnd.ShowModal() != wxID_OK) {
if (set->contains(savename)) return;
else throw ScriptError(_ERROR_1_("can't download image", loadpath));
}
// is the data an image? // is the data an image?
const String& content_type = wnd.out.GetContentType(); if (!wnd.content_type.StartsWith(_("image/"))) throw ScriptError(_ERROR_1_("download not image", loadpath));
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 // add the file to the set
savename = normalize_internal_filename(loadpath + _(".png")); LocalFileName new_image_file = set->newFileName(savename, _(".png"));
savename.Replace(":", "-"); savename = new_image_file.toStringForWriting();
savename.Replace("/", "-"); wnd.image_out.SaveFile(set->nameOut(new_image_file), wxBITMAP_TYPE_PNG);
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) { Image DownloadedImage::generate(const Options& opt) {
+10
View File
@@ -522,6 +522,16 @@ protected:
String savename; 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 // ----------------------------------------------------------------------------- : ImportedImage
/// Load an image from the filesystem /// Load an image from the filesystem
+1 -2
View File
@@ -40,8 +40,7 @@ const char* MSE_AUTHORS[] = {
"Olivier Bocksberger (G-e-n-e-v-e-n-s-i-S)", "Olivier Bocksberger (G-e-n-e-v-e-n-s-i-S)",
"Brendan Hagan (haganbmj)", "Brendan Hagan (haganbmj)",
"Thomas Tkacz (TomTkacz)", "Thomas Tkacz (TomTkacz)",
"CaiCai (247321453)", "CaiCai (247321453)"
"Amy Markey (amyinspace)"
}; };
void AboutWindow::draw(DC& dc) { void AboutWindow::draw(DC& dc) {
+1 -1
View File
@@ -48,8 +48,8 @@ AddCSVWindow::AddCSVWindow(Window* parent, const SetP& set, bool sizer)
s2->Add(CreateButtonSizer(wxOK | wxCANCEL), 1, wxEXPAND, 8); s2->Add(CreateButtonSizer(wxOK | wxCANCEL), 1, wxEXPAND, 8);
s->Add(s2, 0, wxEXPAND | wxALL, 12); s->Add(s2, 0, wxEXPAND | wxALL, 12);
file_browse->SetFocus(); file_browse->SetFocus();
s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
SetSize(500, 110); SetSize(500, 110);
} }
} }
+1 -1
View File
@@ -59,8 +59,8 @@ AddJSONWindow::AddJSONWindow(Window* parent, const SetP& set, bool sizer)
s2->Add(CreateButtonSizer(wxOK | wxCANCEL), 1, wxEXPAND, 8); s2->Add(CreateButtonSizer(wxOK | wxCANCEL), 1, wxEXPAND, 8);
s->Add(s2, 0, wxEXPAND | wxALL, 12); s->Add(s2, 0, wxEXPAND | wxALL, 12);
file_browse->SetFocus(); file_browse->SetFocus();
s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
SetSize(500, 110); SetSize(500, 110);
} }
} }
+1 -1
View File
@@ -199,8 +199,8 @@ AutoReplaceWindow::AutoReplaceWindow(Window* parent, const Game& game)
s4->Add(defaults, 0, wxALL & ~wxRIGHT, 8); s4->Add(defaults, 0, wxALL & ~wxRIGHT, 8);
s4->Add(CreateButtonSizer(wxOK | wxCANCEL), 1, wxALL, 8); s4->Add(CreateButtonSizer(wxOK | wxCANCEL), 1, wxALL, 8);
s->Add(s4, 0, wxEXPAND); s->Add(s4, 0, wxEXPAND);
s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
// Set default size // Set default size
SetSize(350, 450); SetSize(350, 450);
// initialize values // initialize values
+1 -1
View File
@@ -85,8 +85,8 @@ BulkModificationWindow::BulkModificationWindow(Window* parent, const SetP& set,
s1->AddButton(new wxButton(this, wxID_CANCEL)); s1->AddButton(new wxButton(this, wxID_CANCEL));
s1->Realize(); s1->Realize();
s->Add(s1, 1, wxEXPAND | wxALL, 12); s->Add(s1, 1, wxEXPAND | wxALL, 12);
s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
SetSize(600, 400); SetSize(600, 400);
Layout(); Layout();
} }
+4 -8
View File
@@ -20,7 +20,7 @@
// ----------------------------------------------------------------------------- : ExportCardSelectionChoice // ----------------------------------------------------------------------------- : ExportCardSelectionChoice
CardLinkWindow::CardLinkWindow(Window* parent, const SetP& set, const CardP& selected_card, bool sizer) CardLinkWindow::CardLinkWindow(Window* parent, const SetP& set, const CardP& selected_card, bool sizer)
: wxDialog(parent, wxID_ANY, _TITLE_("link cards"), wxPoint(400,-1), wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) : wxDialog(parent, wxID_ANY, _TITLE_("link cards"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
, set(set), parent(parent), selected_card(selected_card) , set(set), parent(parent), selected_card(selected_card)
{ {
// init controls // init controls
@@ -53,8 +53,8 @@ CardLinkWindow::CardLinkWindow(Window* parent, const SetP& set, const CardP& sel
s2->Add(sel_none, 0, wxEXPAND | wxRIGHT, 8); s2->Add(sel_none, 0, wxEXPAND | wxRIGHT, 8);
s2->Add(CreateButtonSizer(wxOK | wxCANCEL), 1, wxEXPAND, 8); s2->Add(CreateButtonSizer(wxOK | wxCANCEL), 1, wxEXPAND, 8);
s->Add(s2, 0, wxEXPAND | (wxALL & ~wxTOP), 8); s->Add(s2, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
SetSize(600,500); SetSize(600,500);
} }
} }
@@ -126,11 +126,7 @@ void CardLinkWindow::onOk(wxCommandEvent&) {
linked_uids.push_back(linked_cards[i]->uid); linked_uids.push_back(linked_cards[i]->uid);
} }
// Find free links // Find free links
unordered_set<String> all_existing_uids; vector<int> free_link_indexes = selected_card->findFreeLinks(linked_uids, set->card_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; int free_link_count = 0;
for (size_t i = 0; i < free_link_indexes.size(); ++i) { for (size_t i = 0; i < free_link_indexes.size(); ++i) {
if (free_link_indexes[i] >= 0) free_link_count++; if (free_link_indexes[i] >= 0) free_link_count++;
@@ -163,7 +159,7 @@ void CardLinkWindow::onOk(wxCommandEvent&) {
// Find reciprocal free slots and make actions // Find reciprocal free slots and make actions
String& selected_uid = selected_card->uid; String& selected_uid = selected_card->uid;
for (size_t i = 0; i < linked_cards.size(); ++i) { for (size_t i = 0; i < linked_cards.size(); ++i) {
int free_link_index = linked_cards[i]->findFreeLink(selected_uid, all_existing_uids); int free_link_index = linked_cards[i]->findFreeLink(selected_uid, set->card_uids);
if (free_link_index >= 0) { if (free_link_index >= 0) {
actions.push_back(make_intrusive<OneWayLinkCardsAction>(linked_cards[i], selected_uid, selected_relation_string, free_link_index)); actions.push_back(make_intrusive<OneWayLinkCardsAction>(linked_cards[i], selected_uid, selected_relation_string, free_link_index));
} }
+1 -1
View File
@@ -140,8 +140,8 @@ CardSelectWindow::CardSelectWindow(Window* parent, const SetP& set, const String
s2->Add(sel_none, 0, wxEXPAND | wxRIGHT, 8); s2->Add(sel_none, 0, wxEXPAND | wxRIGHT, 8);
s2->Add(CreateButtonSizer(wxOK | wxCANCEL), 1, wxEXPAND, 8); s2->Add(CreateButtonSizer(wxOK | wxCANCEL), 1, wxEXPAND, 8);
s->Add(s2, 0, wxEXPAND | (wxALL & ~wxTOP), 8); s->Add(s2, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
SetSize(600,500); SetSize(600,500);
} }
} }
+192 -87
View File
@@ -166,6 +166,7 @@ bool CardListBase::doCopy() {
// put on clipboard // put on clipboard
if (!wxTheClipboard->Open()) return false; if (!wxTheClipboard->Open()) return false;
bool ok = wxTheClipboard->SetData(new CardsOnClipboard(set, _(""), cards_to_copy)); // ignore result bool ok = wxTheClipboard->SetData(new CardsOnClipboard(set, _(""), cards_to_copy)); // ignore result
wxTheClipboard->Flush();
wxTheClipboard->Close(); wxTheClipboard->Close();
return ok; return ok;
} }
@@ -192,6 +193,7 @@ bool CardListBase::doCopyCardAndLinkedCards() {
} }
} }
bool ok = wxTheClipboard->SetData(new CardsOnClipboard(set, _(""), cards_to_copy)); // ignore result bool ok = wxTheClipboard->SetData(new CardsOnClipboard(set, _(""), cards_to_copy)); // ignore result
wxTheClipboard->Flush();
wxTheClipboard->Close(); wxTheClipboard->Close();
return ok; return ok;
} }
@@ -200,6 +202,7 @@ bool CardListBase::doPaste() {
if (!canPaste()) return false; if (!canPaste()) return false;
if (!wxTheClipboard->Open()) return false; if (!wxTheClipboard->Open()) return false;
bool ok = wxTheClipboard->GetData(*drop_target->data_object); bool ok = wxTheClipboard->GetData(*drop_target->data_object);
wxTheClipboard->Flush();
wxTheClipboard->Close(); wxTheClipboard->Close();
if (ok) return parseData(false); if (ok) return parseData(false);
return false; return false;
@@ -210,8 +213,14 @@ bool CardListBase::doDelete() {
vector<CardP> cards_to_delete; vector<CardP> cards_to_delete;
getSelection(cards_to_delete); getSelection(cards_to_delete);
if (cards_to_delete.empty()) return false; 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);
}
// delete cards // delete cards
set->actions.addAction(make_unique<AddCardAction>(REMOVE, *set, cards_to_delete)); set->actions.addAction(make_unique<AddCardAction>(REMOVE, *set, cards_to_delete));
if (other_face) setCard(other_face, true);
return true; return true;
} }
@@ -242,39 +251,45 @@ bool CardListBase::doBulkModification() {
return false; 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++) { for (IndexMap<FieldP, ValueP>::iterator it = card->data.begin(); it != card->data.end(); it++) {
ImageValue* value = dynamic_cast<ImageValue*>(it->get()); ImageValue* value = dynamic_cast<ImageValue*>(it->get());
if (value && !value->filename.empty()) { if (value && !value->filename.empty()) {
RealRect rect(0.0, 0.0, 0.0, 0.0); RealRect rect(0.0, 0.0, 0.0, 0.0);
int degrees = 0; int degrees = 0;
decodeRectFromString(value->filename.toStringForKey(), rect, degrees); if (decodeRectFromString(value->filename.toStringForKey(), rect, degrees)) {
rect = rect.intersect(RealRect(0.0, 0.0, image.GetWidth(), image.GetHeight())); rect = rect.intersect(RealRect(0.0, 0.0, image.GetWidth(), image.GetHeight()));
if (rect.width > 0.0 && rect.height > 0.0) { if (rect.width > 0.0 && rect.height > 0.0) {
Image img = image.GetSubImage(rect); Image img = image.GetSubImage(rect);
img = rotate_image(img, deg_to_rad(360 - degrees)); img = rotate_image(img, deg_to_rad(360 - degrees));
LocalFileName filename = set->newFileName("cropped_image", _(".png")); // a new unique name in the package LocalFileName filename = set->newFileName(_("cropped_image"), _(".png")); // a new unique name in the package
img.SaveFile(set->nameOut(filename), wxBITMAP_TYPE_PNG); img.SaveFile(set->nameOut(filename), wxBITMAP_TYPE_PNG);
value->filename = filename; value->filename = filename;
} }
else { else {
value->filename = LocalFileName(); value->filename = LocalFileName();
//queue_message(MESSAGE_WARNING, _("failed to recover image crop for card '") + card->identification() + _("'"));
}
} }
} }
} }
} }
void CardListBase::parseImageMetadata(CardP& card) void CardListBase::parseImageMetadata(CardP& card) {
{
for (IndexMap<FieldP, ValueP>::iterator it = card->data.begin(); it != card->data.end(); it++) { for (IndexMap<FieldP, ValueP>::iterator it = card->data.begin(); it != card->data.end(); it++) {
ImageValue* value = dynamic_cast<ImageValue*>(it->get()); ImageValue* value = dynamic_cast<ImageValue*>(it->get());
if (value) { if (value && !value->filename.empty()) {
Image img = decodeImageFromString(value->filename.toStringForKey()); Image img;
if (img.IsOk()) { if (decodeImageFromString(value->filename.toStringForKey(), img)) {
LocalFileName filename = set->newFileName(_("decoded_image"), _(".png")); // a new unique name in the package if (img.IsOk()) {
img.SaveFile(set->nameOut(filename), wxBITMAP_TYPE_PNG); LocalFileName filename = set->newFileName(_("decoded_image"), _(".png")); // a new unique name in the package
value->filename = filename; 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() + _("'"));
}
} }
} }
} }
@@ -290,18 +305,11 @@ bool CardListBase::parseUrl(String& url, vector<CardP>& out) {
WebRequestWindow wnd(url); WebRequestWindow wnd(url);
if (wnd.ShowModal() == wxID_OK) { if (wnd.ShowModal() == wxID_OK) {
const String& content_type = wnd.out.GetContentType(); if (wnd.content_type.StartsWith(_("image/"))) {
if (content_type.StartsWith(_("image"))) { parseImage(wnd.image_out, out);
Image img(*wnd.out.GetStream());
if (img.IsOk()) {
parseImage(img, out);
}
else {
queue_message(MESSAGE_ERROR, _ERROR_("web request corrupted"));
}
} }
else if (content_type.StartsWith(_("text"))) { else if (wnd.content_type.StartsWith(_("text/"))) {
String text = wnd.out.AsString(); String text = String(wnd.text_out.data(), wnd.text_out.size());
parseText(text, out); parseText(text, out);
} }
else { else {
@@ -314,16 +322,23 @@ bool CardListBase::parseUrl(String& url, vector<CardP>& out) {
bool CardListBase::parseFiles(wxArrayString& filenames, vector<CardP>& out) { bool CardListBase::parseFiles(wxArrayString& filenames, vector<CardP>& out) {
size_t j = out.size(); size_t j = out.size();
for (size_t i = 0; i < filenames.size(); i++) { for (size_t i = 0; i < filenames.size(); i++) {
// if it's an image file, try to get meta_data if (wxImage::CanRead(filenames[i])) {
Image image_file; // if it's an image file, try to get meta_data
image_file.SetLoadFlags(image_file.GetLoadFlags() & ~wxImage::Load_Verbose); Image image_file;
if (image_file.LoadFile(filenames[i])) { image_file.SetLoadFlags(image_file.GetLoadFlags() & ~wxImage::Load_Verbose);
parseImage(image_file, out); if (image_file.LoadFile(filenames[i])) {
parseImage(image_file, out);
}
else queue_message(MESSAGE_ERROR, _ERROR_("can't load image"));
} else { } else {
// if it's an url, request the data // if it's an url, request the data
std::ifstream ifs(filenames[i].ToStdString()); std::ifstream ifs(filenames[i].ToStdString());
if (ifs.bad() || ifs.fail() || !ifs.good() || !ifs.is_open()) continue; if (ifs.bad() || ifs.fail() || !ifs.good() || !ifs.is_open()) continue;
std::string content((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>())); 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;
wxString text(content); wxString text(content);
if (!parseUrl(text, out)) parseText(text, out); if (!parseUrl(text, out)) parseText(text, out);
} }
@@ -347,9 +362,13 @@ bool CardListBase::parseImage(Image& image, vector<CardP>& out) {
} }
bool CardListBase::parseText(String& text, vector<CardP>& out) { bool CardListBase::parseText(String& text, vector<CardP>& out) {
if (text.size() == 0) {
return false;
}
size_t j = out.size(); size_t j = out.size();
if (size_t pos = text.find("<mse-card-data>") != wxString::npos) { size_t pos = text.find("<mse-card-data>");
text = text.substr(pos + 14, text.find("</mse-card-data>") - pos - 14); if (pos != wxString::npos) {
text = text.substr(pos + 15, text.find("</mse-card-data>") - pos - 15);
} }
try { try {
ScriptValueP sv = json_to_mse(text, set.get()); ScriptValueP sv = json_to_mse(text, set.get());
@@ -357,12 +376,12 @@ bool CardListBase::parseText(String& text, vector<CardP>& out) {
if (ScriptCustomCollection* custom = dynamic_cast<ScriptCustomCollection*>(sv.get())) { if (ScriptCustomCollection* custom = dynamic_cast<ScriptCustomCollection*>(sv.get())) {
for (size_t i = 0; i < custom->value.size(); i++) { for (size_t i = 0; i < custom->value.size(); i++) {
if (ScriptObject<CardP>* c = dynamic_cast<ScriptObject<CardP>*>(custom->value[i].get())) { if (ScriptObject<CardP>* c = dynamic_cast<ScriptObject<CardP>*>(custom->value[i].get())) {
out.push_back(make_intrusive<Card>(*c->getValue())); out.push_back(c->getValue());
} }
} }
} }
} else if (ScriptObject<CardP>* c = dynamic_cast<ScriptObject<CardP>*>(sv.get())) { } else if (ScriptObject<CardP>* c = dynamic_cast<ScriptObject<CardP>*>(sv.get())) {
out.push_back(make_intrusive<Card>(*c->getValue())); out.push_back(c->getValue());
} }
} catch (...) {} } catch (...) {}
@@ -377,54 +396,123 @@ bool CardListBase::parseText(String& text, vector<CardP>& out) {
bool CardListBase::parseData(bool ignore_cards_from_own_card_list) { bool CardListBase::parseData(bool ignore_cards_from_own_card_list) {
wxBusyCursor wait; wxBusyCursor wait;
wxDataFormat format = drop_target->data_object->GetReceivedFormat(); wxDataObjectComposite* composite = drop_target->data_object;
wxDataObject *data = drop_target->data_object->GetObject(format); wxDataFormat format = composite->GetReceivedFormat();
vector<CardP> new_cards; vector<CardP> new_cards;
if (CardsDataObject* card_data = dynamic_cast<CardsDataObject*>(data)) { if (format == CardsDataObject::format) {
String id = ignore_cards_from_own_card_list ? drop_target->ignored_id : _(""); String id = ignore_cards_from_own_card_list ? drop_target->ignored_id : _("");
card_data->getCards(set, id, new_cards); 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);
}
} }
else switch (format.GetType()) else {
{ wxDataObject *data = composite->GetObject(format);
case wxDF_FILENAME:
{
wxFileDataObject* file_data = static_cast<wxFileDataObject*>(data);
wxArrayString filenames = file_data->GetFilenames();
parseFiles(filenames, new_cards);
}
break;
case wxDF_PNG: switch (format.GetType())
{ {
wxImageDataObject* image_data = static_cast<wxImageDataObject*>(data); case wxDF_FILENAME:
Image image = image_data->GetImage(); {
parseImage(image, new_cards); wxFileDataObject* file_data = static_cast<wxFileDataObject*>(data);
} wxArrayString filenames = file_data->GetFilenames();
break; parseFiles(filenames, new_cards);
}
break;
case wxDF_BITMAP: case wxDF_PNG:
{ {
wxBitmapDataObject* bitmap_data = static_cast<wxBitmapDataObject*>(data); wxImageDataObject* image_data = static_cast<wxImageDataObject*>(data);
wxBitmap bitmap = bitmap_data->GetBitmap(); size_t size = image_data->GetDataSize();
Image image = bitmap.ConvertToImage(); if (size < 1) {
parseImage(image, new_cards); queue_message(MESSAGE_ERROR, _("DEBUG: ImageDataObject corrupted"));
} return false;
break; }
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_UNICODETEXT: case wxDF_BITMAP:
case wxDF_TEXT: {
case wxDF_HTML: wxBitmapDataObject* bitmap_data = static_cast<wxBitmapDataObject*>(data);
{ size_t size = bitmap_data->GetDataSize();
wxTextDataObject* text_data = static_cast<wxTextDataObject*>(data); if (size < 1) {
String text = text_data->GetText(); queue_message(MESSAGE_ERROR, _("DEBUG: BitmapDataObject corrupted"));
if (!parseUrl(text, new_cards)) parseText(text, new_cards); return false;
} }
break; 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;
default: case wxDF_UNICODETEXT:
{ case wxDF_TEXT:
queue_message(MESSAGE_ERROR, _ERROR_("unknown data format")); 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;
default:
{
queue_message(MESSAGE_ERROR, _ERROR_("unknown data format"));
}
} }
} }
@@ -441,15 +529,12 @@ bool CardListBase::canLink() const {
vector<CardP> selected_cards; vector<CardP> selected_cards;
getSelection(selected_cards); getSelection(selected_cards);
if (selected_cards.size() != 1) return false; 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]; CardP card = selected_cards[0];
return card->findFreeLink(card->uid, all_existing_uids) >= 0; return card->findFreeLink(card->uid, set->card_uids) >= 0;
} }
bool CardListBase::doLink() { bool CardListBase::doLink() {
CardLinkWindow wnd(this, set, getCard()); CardLinkWindow wnd(this, set, getCard());
wnd.CentreOnParent();
if (wnd.ShowModal() == wxID_OK) { if (wnd.ShowModal() == wxID_OK) {
// The actual linking is done in this window's onOk function // The actual linking is done in this window's onOk function
return true; return true;
@@ -476,7 +561,23 @@ bool CardListBase::compareItems(void* a, void* b) const {
// compare sort keys // compare sort keys
int cmp = smart_compare( va->getSortKey(), vb->getSortKey() ); int cmp = smart_compare( va->getSortKey(), vb->getSortKey() );
if (cmp != 0) return cmp < 0; if (cmp != 0) return cmp < 0;
// equal values, compare alternate sort key // 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;
}
}
if (alternate_sort_field) { if (alternate_sort_field) {
ValueP va = reinterpret_cast<Card*>(a)->data[alternate_sort_field]; ValueP va = reinterpret_cast<Card*>(a)->data[alternate_sort_field];
ValueP vb = reinterpret_cast<Card*>(b)->data[alternate_sort_field]; ValueP vb = reinterpret_cast<Card*>(b)->data[alternate_sort_field];
@@ -516,6 +617,8 @@ void CardListBase::rebuild() {
GameSettings& gs = settings.gameSettingsFor(*set->game); GameSettings& gs = settings.gameSettingsFor(*set->game);
sort_ascending = gs.sort_cards_ascending; sort_ascending = gs.sort_cards_ascending;
sort_by_column = -1; sort_by_column = -1;
sort_by_column2 = -1;
sort_by_column3 = -1;
long i = 0; long i = 0;
FOR_EACH(f, column_fields) { FOR_EACH(f, column_fields) {
if (f->name == gs.sort_cards_by) { if (f->name == gs.sort_cards_by) {
@@ -651,7 +754,8 @@ void CardListBase::onChar(wxKeyEvent& ev) {
} }
} }
void CardListBase::onBeginDrag(wxListEvent&) { void CardListBase::onBeginDrag(wxListEvent& ev) {
ev.Skip();
drop_timer.Start(200, wxTIMER_ONE_SHOT); drop_timer.Start(200, wxTIMER_ONE_SHOT);
} }
@@ -697,6 +801,7 @@ void CardListBase::onContextMenu(wxContextMenuEvent&) {
add_menu_item_tr(&m, wxID_PASTE, "paste", "paste_card"); add_menu_item_tr(&m, wxID_PASTE, "paste", "paste_card");
m.AppendSeparator(); m.AppendSeparator();
add_menu_item_tr(&m, ID_CARD_ADD, "card_add", "add card"); 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_REMOVE, "card_del", "remove card");
add_menu_item_tr(&m, ID_CARD_LINK, settings.darkModePrefix() + "card_link", "link card"); add_menu_item_tr(&m, ID_CARD_LINK, settings.darkModePrefix() + "card_link", "link card");
PopupMenu(&m); PopupMenu(&m);
+1 -1
View File
@@ -34,8 +34,8 @@ CardListColumnSelectDialog::CardListColumnSelectDialog(Window* parent, const Gam
s2->Add(s3, 0, wxEXPAND | (wxALL & ~wxTOP), 4); s2->Add(s3, 0, wxEXPAND | (wxALL & ~wxTOP), 4);
s->Add(s2 , 1, wxEXPAND | wxALL, 4); s->Add(s2 , 1, wxEXPAND | wxALL, 4);
s->Add(CreateButtonSizer(wxOK | wxCANCEL) , 0, wxEXPAND | wxALL, 8); s->Add(CreateButtonSizer(wxOK | wxCANCEL) , 0, wxEXPAND | wxALL, 8);
s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
// Set default size // Set default size
SetSize(350, 450); SetSize(350, 450);
// Initialize order list // Initialize order list
+3 -1
View File
@@ -16,7 +16,7 @@
ItemList::ItemList(Window* parent, int id, long additional_style, bool multi_sel) 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)) : wxListView(parent, id, wxDefaultPosition, wxDefaultSize, additional_style | wxLC_REPORT | wxLC_VIRTUAL | (multi_sel ? 0 : wxLC_SINGLE_SEL))
, selected_item_pos(-1) , selected_item_pos(-1)
, sort_by_column(-1), sort_ascending(true) , sort_by_column(-1), sort_by_column2(-1), sort_by_column3(-1), sort_ascending(true)
{ {
// create image list // create image list
wxImageList* il = new wxImageList(18,14); wxImageList* il = new wxImageList(18,14);
@@ -263,6 +263,8 @@ void ItemList::onColumnClick(wxListEvent& ev) {
new_sort_by_column = -1; // 3rd click on same column -> don't sort new_sort_by_column = -1; // 3rd click on same column -> don't sort
} }
} else { } else {
sort_by_column3 = sort_by_column2;
sort_by_column2 = sort_by_column;
sort_ascending = true; sort_ascending = true;
} }
sortBy(new_sort_by_column, sort_ascending); sortBy(new_sort_by_column, sort_ascending);
+2
View File
@@ -107,6 +107,8 @@ protected:
VoidP selected_item; ///< The currently selected item 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 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_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 bool sort_ascending; ///< Sort order
vector<VoidP> sorted_list; ///< Sorted list of items, can be considered a map: pos->item vector<VoidP> sorted_list; ///< Sorted list of items, can be considered a map: pos->item
+2
View File
@@ -109,6 +109,7 @@ bool KeywordList::doCopy() {
if (!canCopy()) return false; if (!canCopy()) return false;
if (!wxTheClipboard->Open()) return false; if (!wxTheClipboard->Open()) return false;
bool ok = wxTheClipboard->SetData(new KeywordDataObject(set, getKeyword())); // ignore result bool ok = wxTheClipboard->SetData(new KeywordDataObject(set, getKeyword())); // ignore result
wxTheClipboard->Flush();
wxTheClipboard->Close(); wxTheClipboard->Close();
return ok; return ok;
} }
@@ -125,6 +126,7 @@ bool KeywordList::doPaste() {
if (!wxTheClipboard->Open()) return false; if (!wxTheClipboard->Open()) return false;
KeywordDataObject data; KeywordDataObject data;
bool ok = wxTheClipboard->GetData(data); bool ok = wxTheClipboard->GetData(data);
wxTheClipboard->Flush();
wxTheClipboard->Close(); wxTheClipboard->Close();
if (!ok) return false; if (!ok) return false;
// add keyword to set // add keyword to set
+1
View File
@@ -59,6 +59,7 @@ void TextCtrl::updateSize() {
viewer.bounding_box.width = cs.GetWidth() - 2; viewer.bounding_box.width = cs.GetWidth() - 2;
viewer.bounding_box.height = cs.GetHeight() - 2; viewer.bounding_box.height = cs.GetHeight() - 2;
viewers.front()->getEditor()->determineSize(true); viewers.front()->getEditor()->determineSize(true);
InvalidateBestSize();
} }
void TextCtrl::setValue(String* value, bool untagged) { void TextCtrl::setValue(String* value, bool untagged) {
+3 -3
View File
@@ -68,12 +68,12 @@ public:
/// Show a dialog to inform the user that updates are available (if there are any) /// Show a dialog to inform the user that updates are available (if there are any)
/// Call check_updates first. Call this function from an onIdle loop /// Call check_updates first. Call this function from an onIdle loop
inline void show_update_dialog(Window* parent) { inline void show_update_dialog(Window* set_window) {
if (shown_dialog || check_status != FOUND) return; // we already have the latest version, or this has already been displayed. if (shown_dialog || check_status != FOUND) return; // we already have the latest version, or this has already been displayed.
shown_dialog = true; shown_dialog = true;
wxMessageDialog dial = wxMessageDialog(parent, _LABEL_("updates found"), _TITLE_("updates available"), wxYES_NO); wxMessageDialog dial = wxMessageDialog(set_window, _LABEL_("updates found"), _TITLE_("updates available"), wxYES_NO);
if (dial.ShowModal() == wxID_YES) { if (dial.ShowModal() == wxID_YES) {
(new PackagesWindow(parent))->Show(); (new PackagesWindow(set_window))->Show();
} }
} }
+2 -2
View File
@@ -44,11 +44,11 @@ HtmlExportWindow::HtmlExportWindow(Window* parent, const SetP& set, const Export
s2->Add(s3, 7, wxEXPAND | wxLEFT, 8); s2->Add(s3, 7, wxEXPAND | wxLEFT, 8);
s->Add(s2, 1, wxEXPAND | wxALL, 4); s->Add(s2, 1, wxEXPAND | wxALL, 4);
s->Add(CreateButtonSizer(wxOK | wxCANCEL) , 0, wxEXPAND | wxALL, 8); s->Add(CreateButtonSizer(wxOK | wxCANCEL) , 0, wxEXPAND | wxALL, 8);
s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
SetSize(700,500); SetSize(700,500);
// list // list
list->showData<ExportTemplate>(set->game->name() + _("-*")); list->showData<ExportTemplate>(set->game->name() + _("*"));
list->select(settings.gameSettingsFor(*set->game).default_export); list->select(settings.gameSettingsFor(*set->game).default_export);
} }
+1 -1
View File
@@ -229,8 +229,8 @@ ImageSliceWindow::ImageSliceWindow(Window* parent, const Image& source, const St
s5->AddStretchSpacer(1); s5->AddStretchSpacer(1);
s->Add(s5, 0, wxEXPAND); s->Add(s5, 0, wxEXPAND);
s->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxALL, 8); s->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxALL, 8);
s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
// Only now do we allow events to be processed. // Only now do we allow events to be processed.
initialized = true; initialized = true;
updateControls(); updateControls();
+1 -1
View File
@@ -43,8 +43,8 @@ ImagesExportWindow::ImagesExportWindow(Window* parent, const SetP& set, const Ex
wxSizer* s3 = ExportWindowBase::Create(); wxSizer* s3 = ExportWindowBase::Create();
s->Add(s3, 1, wxEXPAND | (wxALL & ~wxTOP), 8); s->Add(s3, 1, wxEXPAND | (wxALL & ~wxTOP), 8);
s->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | (wxALL & ~wxTOP), 8); s->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | (wxALL & ~wxTOP), 8);
s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
SetSize(500,-1); SetSize(500,-1);
} }
+117 -14
View File
@@ -10,6 +10,8 @@
#include <gui/new_window.hpp> #include <gui/new_window.hpp>
#include <gui/control/gallery_list.hpp> #include <gui/control/gallery_list.hpp>
#include <gui/control/package_list.hpp> #include <gui/control/package_list.hpp>
#include <gui/downloadable_installers.hpp>
#include <data/installer.hpp>
#include <data/game.hpp> #include <data/game.hpp>
#include <data/stylesheet.hpp> #include <data/stylesheet.hpp>
#include <data/set.hpp> #include <data/set.hpp>
@@ -56,8 +58,8 @@ NewSetWindow::NewSetWindow(Window* parent)
s->Add(s3, wxSizerFlags().Expand().Border(wxALL, 6)); s->Add(s3, wxSizerFlags().Expand().Border(wxALL, 6));
s->Add(stylesheet_list, 0, wxEXPAND | (wxALL & ~wxTOP), 4); s->Add(stylesheet_list, 0, wxEXPAND | (wxALL & ~wxTOP), 4);
s->Add(CreateButtonSizer(wxOK | wxCANCEL) , 0, wxEXPAND | wxALL, 8); s->Add(CreateButtonSizer(wxOK | wxCANCEL) , 0, wxEXPAND | wxALL, 8);
s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
// Resize // Resize
Layout(); Layout();
wxSize min_size = GetSizer()->GetMinSize() + GetSize() - GetClientSize(); wxSize min_size = GetSizer()->GetMinSize() + GetSize() - GetClientSize();
@@ -177,10 +179,15 @@ StyleSheetP select_stylesheet(const Game& game, const String& failed_name) {
SelectStyleSheetWindow::SelectStyleSheetWindow(Window* parent, const Game& game, const String& failed_name) SelectStyleSheetWindow::SelectStyleSheetWindow(Window* parent, const Game& game, const String& failed_name)
: wxDialog(parent, wxID_ANY, _TITLE_("select stylesheet"), wxDefaultPosition, wxSize(830,320), wxDEFAULT_DIALOG_STYLE) : wxDialog(parent, wxID_ANY, _TITLE_("select stylesheet"), wxDefaultPosition, wxSize(830,320), wxDEFAULT_DIALOG_STYLE)
, game(game) , game(game)
, failed_name(failed_name)
{ {
wxBusyCursor wait; wxBusyCursor wait;
// init controls // init controls
stylesheet_list = new PackageList (this, ID_STYLESHEET_LIST); ok_button = new wxButton (this, wxID_OK);
cancel_button = new wxButton (this, wxID_CANCEL);
find_online_button = new wxButton (this, ID_DOWNLOAD_STYLESHEET, _BUTTON_("find package online"));
stylesheet_list = new PackageList (this, ID_STYLESHEET_LIST);
find_online_status_text = new wxStaticText(this, wxID_ANY, _(""));
wxStaticText* description = new wxStaticText(this, ID_GAME_LIST, _LABEL_1_("stylesheet not found", failed_name)); wxStaticText* description = new wxStaticText(this, ID_GAME_LIST, _LABEL_1_("stylesheet not found", failed_name));
wxStaticText* stylesheet_text = new wxStaticText(this, ID_STYLESHEET_LIST, _LABEL_("style type")); wxStaticText* stylesheet_text = new wxStaticText(this, ID_STYLESHEET_LIST, _LABEL_("style type"));
@@ -196,17 +203,25 @@ SelectStyleSheetWindow::SelectStyleSheetWindow(Window* parent, const Game& game,
s2->Add(stylesheet_filter, 1, wxRIGHT, 4); s2->Add(stylesheet_filter, 1, wxRIGHT, 4);
s->Add(s2, wxSizerFlags().Expand().Border(wxALL, 6)); s->Add(s2, wxSizerFlags().Expand().Border(wxALL, 6));
s->Add(stylesheet_list, 0, wxEXPAND | (wxALL & ~wxTOP), 4); s->Add(stylesheet_list, 0, wxEXPAND | (wxALL & ~wxTOP), 4);
s->Add(CreateButtonSizer(wxOK | wxCANCEL) , 0, wxEXPAND | wxALL, 8); wxBoxSizer* s3 = new wxBoxSizer(wxHORIZONTAL);
s->SetSizeHints(this); s3->Add(find_online_button, 0, wxRIGHT, 8);
s3->Add(find_online_status_text, 1, wxALIGN_CENTER_VERTICAL);
s3->AddStretchSpacer();
s3->Add(ok_button, 0, wxRIGHT, 4);
s3->Add(cancel_button, 0);
s->Add(s3, 0, wxEXPAND | wxALL, 8);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
// init list // init list
stylesheet_list->showData<StyleSheet>(game.name() + _("-*")); stylesheet_list->showData<StyleSheet>(game.name() + _("*"));
stylesheet_list->select(settings.gameSettingsFor(game).default_stylesheet); stylesheet_list->select(settings.gameSettingsFor(game).default_stylesheet);
// Resize // Resize
Layout(); Layout();
wxSize min_size = GetSizer()->GetMinSize() + GetSize() - GetClientSize(); wxSize min_size = GetSizer()->GetMinSize() + GetSize() - GetClientSize();
SetSize(830,min_size.y); SetSize(830,min_size.y);
UpdateWindowUI(wxUPDATE_UI_RECURSE); UpdateWindowUI(wxUPDATE_UI_RECURSE);
// start downloading the installer list
downloadable_installers.download();
} }
void SelectStyleSheetWindow::onStyleSheetSelect(wxCommandEvent&) { void SelectStyleSheetWindow::onStyleSheetSelect(wxCommandEvent&) {
@@ -228,6 +243,87 @@ void SelectStyleSheetWindow::onStylesheetFilterUpdate(wxCommandEvent&) {
} }
} }
void SelectStyleSheetWindow::onFindOnline(wxCommandEvent&) {
if (searching_online) return;
searching_online = true;
find_online_status_text->SetLabel(_LABEL_("searching online"));
find_online_button->Enable(false);
//downloadable_installers.download();
}
void SelectStyleSheetWindow::tryAutoInstall() {
auto_installing = true;
searching_online = false;
wxBusyCursor busy;
// search for missing stylesheet
InstallablePackages packages;
package_manager.findAllInstalledPackages(packages);
FOR_EACH(inst, downloadable_installers.installers) {
merge(packages, inst);
}
FOR_EACH(p, packages) {
if (!p) continue;
p->determineStatus();
}
InstallablePackageP target;
FOR_EACH(p, packages) {
if (!p || !p->description) continue;
if (p->description->name == failed_name) {
target = p;
break;
}
}
if (!target) {
find_online_status_text->SetLabel(_LABEL_("searching online fail"));
auto_installing = false;
return;
}
try {
// update UI
find_online_status_text->SetLabel(_LABEL_("found online downloading"));
ok_button->Enable(false);
cancel_button->Enable(false);
stylesheet_list->Enable(false);
stylesheet_filter->Enable(false);
Layout();
Refresh();
Update();
wxSafeYield(this, true);
// resolve dependencies
PackageAction where = is_install_local(settings.install_type) ? PACKAGE_ACT_LOCAL : PACKAGE_ACT_GLOBAL;
bool action_ok = set_package_action(packages, target, PACKAGE_ACT_INSTALL | where);
if (!action_ok) throw Error(_("can't resolve dependencies"));
// download stylesheet and dependencies
FOR_EACH(p, packages) {
if (!p->has(PACKAGE_ACT_INSTALL)) continue;
p->ensureIsDownloaded();
}
// update UI
find_online_status_text->SetLabel(_LABEL_("found online installing"));
Layout();
Refresh();
Update();
wxSafeYield(this, true);
// install stylesheet and dependencies
FOR_EACH(p, packages) {
if (!p->has(PACKAGE_ACT_INSTALL)) continue;
bool package_ok = package_manager.install(*p);
if (!package_ok) throw Error(_("install package failed"));
}
// auto select stylesheet and exit
stylesheet = StyleSheet::byGameAndName(game, failed_name);
EndModal(wxID_OK);
} catch (const Error& e) {
handle_error(e);
auto_installing = false;
find_online_status_text->SetLabel(_LABEL_("found online fail"));
ok_button->Enable(true);
cancel_button->Enable(true);
stylesheet_list->Enable(true);
stylesheet_filter->Enable(true);
}
}
void SelectStyleSheetWindow::OnOK(wxCommandEvent&) { void SelectStyleSheetWindow::OnOK(wxCommandEvent&) {
done(); done();
} }
@@ -245,22 +341,29 @@ void SelectStyleSheetWindow::done() {
void SelectStyleSheetWindow::onUpdateUI(wxUpdateUIEvent& ev) { void SelectStyleSheetWindow::onUpdateUI(wxUpdateUIEvent& ev) {
switch (ev.GetId()) { switch (ev.GetId()) {
case wxID_OK: case wxID_OK:
ev.Enable(stylesheet_list->hasSelection()); if (!auto_installing) ev.Enable(stylesheet_list->hasSelection());
break; break;
} }
} }
void SelectStyleSheetWindow::onIdle(wxIdleEvent& ev) { void SelectStyleSheetWindow::onIdle(wxIdleEvent& ev) {
// Stuff that must be done in the main thread if (searching_online && !auto_installing) {
//handle_pending_errors(); // errors are ignored until set window is shown // still downloading?
if (!downloadable_installers.download()) {
return;
}
// installer list ready
tryAutoInstall();
}
} }
BEGIN_EVENT_TABLE(SelectStyleSheetWindow, wxDialog) BEGIN_EVENT_TABLE(SelectStyleSheetWindow, wxDialog)
EVT_GALLERY_SELECT (ID_STYLESHEET_LIST, SelectStyleSheetWindow::onStyleSheetSelect) EVT_GALLERY_SELECT (ID_STYLESHEET_LIST, SelectStyleSheetWindow::onStyleSheetSelect)
EVT_GALLERY_ACTIVATE(ID_STYLESHEET_LIST, SelectStyleSheetWindow::onStyleSheetActivate) EVT_GALLERY_ACTIVATE(ID_STYLESHEET_LIST, SelectStyleSheetWindow::onStyleSheetActivate)
EVT_COMMAND_RANGE(ID_STYLESHEET_FILTER, ID_STYLESHEET_FILTER, wxEVT_COMMAND_TEXT_UPDATED, SelectStyleSheetWindow::onStylesheetFilterUpdate) EVT_COMMAND_RANGE (ID_STYLESHEET_FILTER, ID_STYLESHEET_FILTER, wxEVT_COMMAND_TEXT_UPDATED, SelectStyleSheetWindow::onStylesheetFilterUpdate)
EVT_BUTTON (wxID_OK, SelectStyleSheetWindow::OnOK) EVT_BUTTON (ID_DOWNLOAD_STYLESHEET, SelectStyleSheetWindow::onFindOnline)
EVT_UPDATE_UI (wxID_ANY, SelectStyleSheetWindow::onUpdateUI) EVT_BUTTON (wxID_OK, SelectStyleSheetWindow::OnOK)
EVT_IDLE ( SelectStyleSheetWindow::onIdle) EVT_UPDATE_UI (wxID_ANY, SelectStyleSheetWindow::onUpdateUI)
EVT_IDLE ( SelectStyleSheetWindow::onIdle)
END_EVENT_TABLE () END_EVENT_TABLE ()
+13 -3
View File
@@ -83,20 +83,30 @@ private:
// gui items // gui items
PackageList* stylesheet_list; PackageList* stylesheet_list;
FilterCtrl* stylesheet_filter; FilterCtrl* stylesheet_filter;
String stylesheet_filter_value; String stylesheet_filter_value;
wxButton* ok_button, *cancel_button;
wxButton* find_online_button;
wxStaticText* find_online_status_text;
bool searching_online = false;
bool auto_installing = false;
String failed_name;
// --------------------------------------------------- : events // --------------------------------------------------- : events
void onStyleSheetSelect (wxCommandEvent&); void onStyleSheetSelect (wxCommandEvent&);
void onStyleSheetActivate(wxCommandEvent&); void onStyleSheetActivate(wxCommandEvent&);
void onStylesheetFilterUpdate(wxCommandEvent&); void onStylesheetFilterUpdate(wxCommandEvent&);
void onFindOnline(wxCommandEvent&);
virtual void OnOK(wxCommandEvent&); virtual void OnOK(wxCommandEvent&);
void onUpdateUI(wxUpdateUIEvent&); void onUpdateUI(wxUpdateUIEvent&);
void onIdle(wxIdleEvent&); void onIdle(wxIdleEvent&);
void tryAutoInstall();
// we are done, close the window // we are done, close the window
void done(); void done();
}; };
+59 -8
View File
@@ -16,16 +16,34 @@
/// A list of installed and downloadable packages /// A list of installed and downloadable packages
class PackageUpdateList : public TreeList { class PackageUpdateList : public TreeList {
private:
class TreeItem;
public: public:
typedef intrusive_ptr<TreeItem> TreeItemP;
PackageUpdateList(Window* parent, const InstallablePackages& packages, bool show_only_installable, int id = wxID_ANY); PackageUpdateList(Window* parent, const InstallablePackages& packages, bool show_only_installable, int id = wxID_ANY);
~PackageUpdateList(); ~PackageUpdateList();
inline InstallablePackageP getSelection() const { inline InstallablePackageP getSelectedPackage() const {
return selection == NOTHING ? InstallablePackageP() : get(selection); TreeItem* ti = getSelectedItem();
return ti ? ti->package : InstallablePackageP();
} }
inline InstallablePackageP get(size_t item) const { inline bool selectionIsGroup() const {
return static_pointer_cast<TreeItem>(items[item])->package; TreeItem* ti = getSelectedItem();
return ti && !ti->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: protected:
@@ -38,15 +56,48 @@ protected:
int columnWidth(size_t column) const override; int columnWidth(size_t column) const override;
private: 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 /// The list of packages we are displaying
const InstallablePackages& packages; const InstallablePackages& packages;
/// Show only packages with an installer? /// Show only packages with an installer?
bool show_only_installable; bool show_only_installable;
class TreeItem;
public:
typedef intrusive_ptr<TreeItem> TreeItemP;
private:
class TreeItem : public Item { class TreeItem : public Item {
public: public:
TreeItem() : position_type(TYPE_OTHER), position_hint(1000000) {} TreeItem() : position_type(TYPE_OTHER), position_hint(1000000) {}
+90 -56
View File
@@ -18,7 +18,6 @@
#include <data/settings.hpp> #include <data/settings.hpp>
#include <gfx/gfx.hpp> #include <gfx/gfx.hpp>
#include <wx/wfstream.h> #include <wx/wfstream.h>
#include <wx/webrequest.h>
#include <wx/dcbuffer.h> #include <wx/dcbuffer.h>
#include <wx/progdlg.h> #include <wx/progdlg.h>
#include <wx/tglbtn.h> #include <wx/tglbtn.h>
@@ -86,31 +85,36 @@ void PackageInfoPanel::draw(DC& dc) {
icon_w = icon.GetWidth(); icon_w = icon.GetWidth();
icon_h = icon.GetHeight(); icon_h = icon.GetHeight();
} }
dc.DrawBitmap(icon, x+(max_size-icon_w)/2, y+(max_size-icon_h)/2); dc.DrawBitmap(icon, x+(max_size-icon_w)/2, y+(max_size-icon_h)/2 + 2);
x += max_size; x += max_size;
} }
// package name // package info
x += 7; x += 7;
dc.SetFont(wxFont(16, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, _("Arial"))); dc.SetFont(wxFont(16, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, _("Arial")));
dc.DrawText(d.full_name, x, y); 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);
y += dc.GetCharHeight() + 7; y += dc.GetCharHeight() + 7;
// version
dc.SetFont(*wxNORMAL_FONT); dc.SetFont(*wxNORMAL_FONT);
int dy = dc.GetCharHeight() + 3; int dy = dc.GetCharHeight() + 3;
dc.DrawText(_LABEL_("installed version"), x, y); dc.DrawText(_LABEL_("folder name"), x, y);
dc.DrawText(_LABEL_("installable version"), x, y + 1*dy); dc.DrawText(_LABEL_("installed version"), x, y + 1*dy);
dc.DrawText(_LABEL_("installable version"), x, y + 2*dy);
//dc.DrawText(_LABEL_("installer size"), x, y + 2*dy); //dc.DrawText(_LABEL_("installer size"), x, y + 2*dy);
//dc.DrawText(_LABEL_("installer status"), x, y + 3*dy); //dc.DrawText(_LABEL_("installer status"), x, y + 3*dy);
// text size? // text size?
int dx = 0, max_dx = 0; 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_("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_("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 size"), &dx, nullptr); max_dx = max(max_dx, dx);
//dc.GetTextExtent(_LABEL_("installer status"), &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; x += max_dx + 5;
dc.DrawText(package->installed ? package->installed->version.toString() : _LABEL_("no version"), x, y); dc.DrawText(d.name, x, y);
dc.DrawText(package->installer ? package->description->version.toString() : _LABEL_("no version"), x, y + 1*dy); 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(_("?"), x, y + 2*dy); //dc.DrawText(_("?"), x, y + 2*dy);
//dc.DrawText(_("?"), x, y + 3*dy); //dc.DrawText(_("?"), x, y + 3*dy);
} }
@@ -126,9 +130,7 @@ END_EVENT_TABLE()
// ----------------------------------------------------------------------------- : PackagesWindow // ----------------------------------------------------------------------------- : PackagesWindow
enum Action { DEFINE_EVENT_TYPE(EVENT_PACKAGE_LIST_CHANGED);
KEEP, INSTALL, UPGRADE, REMOVE
};
PackagesWindow::PackagesWindow(Window* parent, bool download_package_list) PackagesWindow::PackagesWindow(Window* parent, bool download_package_list)
: waiting_for_list(download_package_list) : waiting_for_list(download_package_list)
@@ -195,6 +197,7 @@ void PackagesWindow::init(Window* parent, bool show_only_installable) {
v2->Add(keep_button, 0, wxEXPAND | wxBOTTOM, 4); v2->Add(keep_button, 0, wxEXPAND | wxBOTTOM, 4);
v2->AddStretchSpacer(); v2->AddStretchSpacer();
v2->Add(remove_button, 0, wxEXPAND | wxBOTTOM, 0); v2->Add(remove_button, 0, wxEXPAND | wxBOTTOM, 0);
v2->SetMinSize(wxSize(170, -1));
h->Add(v2); h->Add(v2);
v->Add(h, 0, wxEXPAND | (wxALL & ~wxTOP), 8); v->Add(h, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
wxBoxSizer* h2 = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* h2 = new wxBoxSizer(wxHORIZONTAL);
@@ -202,7 +205,7 @@ void PackagesWindow::init(Window* parent, bool show_only_installable) {
h2->AddStretchSpacer(); h2->AddStretchSpacer();
h2->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | (wxALL & ~wxTOP), 8); h2->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | (wxALL & ~wxTOP), 8);
v->Add(h2, 0, wxEXPAND); v->Add(h2, 0, wxEXPAND);
v->SetMinSize(800,600); v->SetMinSize(820,650);
SetSizerAndFit(v); SetSizerAndFit(v);
wxUpdateUIEvent::SetMode(wxUPDATE_UI_PROCESS_SPECIFIED); wxUpdateUIEvent::SetMode(wxUPDATE_UI_PROCESS_SPECIFIED);
@@ -212,24 +215,27 @@ void PackagesWindow::init(Window* parent, bool show_only_installable) {
PackagesWindow::~PackagesWindow() { PackagesWindow::~PackagesWindow() {
} }
void PackagesWindow::onPackageSelect(wxCommandEvent& ev) { void PackagesWindow::onPackageSelect(wxCommandEvent& ev) {
package_info->setPackage(package = package_list->getSelection()); package_info->setPackage(package = package_list->getSelectedPackage());
UpdateWindowUI(wxUPDATE_UI_RECURSE); UpdateWindowUI(wxUPDATE_UI_RECURSE);
} }
void PackagesWindow::onActionChange(wxCommandEvent& ev) { void PackagesWindow::onActionChange(wxCommandEvent& ev) {
if (package) { PackageAction act = ev.GetId() == ID_INSTALL ? PACKAGE_ACT_INSTALL
PackageAction act = ev.GetId() == ID_INSTALL ? PACKAGE_ACT_INSTALL : ev.GetId() == ID_UPGRADE ? PACKAGE_ACT_INSTALL
: ev.GetId() == ID_UPGRADE ? PACKAGE_ACT_INSTALL : ev.GetId() == ID_REMOVE ? PACKAGE_ACT_REMOVE
: ev.GetId() == ID_REMOVE ? PACKAGE_ACT_REMOVE : PACKAGE_ACT_NOTHING;
: PACKAGE_ACT_NOTHING; act = act | where;
act = act | where; // set action
// set action package_list->forEachSelectedPackage(
set_package_action(installable_packages, package, act); [&](const InstallablePackageP& p) {
package_list->Refresh(false); if (p->can(act)) {
UpdateWindowUI(wxUPDATE_UI_RECURSE); set_package_action(installable_packages, p, act);
} }
}
);
package_list->Refresh(false);
UpdateWindowUI(wxUPDATE_UI_RECURSE);
} }
void PackagesWindow::onOk(wxCommandEvent& ev) { void PackagesWindow::onOk(wxCommandEvent& ev) {
@@ -252,7 +258,7 @@ void PackagesWindow::onOk(wxCommandEvent& ev) {
} }
} }
// anything to do? // anything to do?
if (!to_change) { if (!to_change && !app_change) {
ev.Skip(); ev.Skip();
return; return;
} }
@@ -272,8 +278,6 @@ void PackagesWindow::onOk(wxCommandEvent& ev) {
this, this,
wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_SMOOTH | wxSTAY_ON_TOP wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_SMOOTH | wxSTAY_ON_TOP
); );
// Clear package list
package_manager.reset();
// Download installers // Download installers
int package_pos = 0, step = 0; int package_pos = 0, step = 0;
FOR_EACH(ip, installable_packages) { FOR_EACH(ip, installable_packages) {
@@ -282,20 +286,7 @@ void PackagesWindow::onOk(wxCommandEvent& ev) {
if (!progress.Update(step++, String::Format(_ERROR_("downloading updates"), ++package_pos, to_download))) { if (!progress.Update(step++, String::Format(_ERROR_("downloading updates"), ++package_pos, to_download))) {
return; // aborted return; // aborted
} }
// download installer ip->ensureIsDownloaded();
wxWebRequestSync request = wxWebSessionSync::GetDefault().CreateRequest(ip->installer->installer_url);
auto const result = request.Execute();
if (!result) {
throw Error(_ERROR_2_("can't download installer", ip->description->name, ip->installer->installer_url));
}
wxInputStream* is(request.GetResponse().GetStream());
ip->installer->installer_file = wxFileName::CreateTempFileName(_("mse-installer"));
wxFileOutputStream os(ip->installer->installer_file);
os.Write(*is);
os.Close();
// open installer
ip->installer->installer = make_intrusive<Installer>();
ip->installer->installer->open(ip->installer->installer_file);
} }
} }
// Install stuff // Install stuff
@@ -360,6 +351,8 @@ void PackagesWindow::onOk(wxCommandEvent& ev) {
// } // }
//} //}
} }
// Notify that packages have changed
sendEvent();
// Continue event propagation into the dialog window so that it closes. // Continue event propagation into the dialog window so that it closes.
ev.Skip(); ev.Skip();
//%% TODO: will we delete packages? //%% TODO: will we delete packages?
@@ -369,27 +362,63 @@ void PackagesWindow::onOk(wxCommandEvent& ev) {
} }
void PackagesWindow::onUpdateUI(wxUpdateUIEvent& ev) { void PackagesWindow::onUpdateUI(wxUpdateUIEvent& ev) {
bool is_group = package_list->selectionIsGroup();
wxToggleButton* w = (wxToggleButton*)ev.GetEventObject(); wxToggleButton* w = (wxToggleButton*)ev.GetEventObject();
switch (ev.GetId()) { switch (ev.GetId()) {
case ID_KEEP: case ID_KEEP:
w->SetValue(package && package->has(PACKAGE_ACT_NOTHING)); w->SetValue(
w->Enable (package && package->can(PACKAGE_ACT_NOTHING | where)); package_list->allSelectedPackages([&](const InstallablePackageP& p) {
w->SetLabel(package && package->installed ? _BUTTON_("keep package") : _BUTTON_("don't install package")); 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"));
break; break;
case ID_INSTALL: case ID_INSTALL:
w->SetValue(package && package->has(PACKAGE_ACT_INSTALL | where)); w->SetValue(
w->Enable (package && package->can(PACKAGE_ACT_INSTALL | where)); package_list->allSelectedPackages([&](const InstallablePackageP& p) {
w->SetLabel(!(package && package->installed) ? _BUTTON_("install package") return p->has(PACKAGE_ACT_INSTALL | where) ||
: (package && package->has(PACKAGE_UPDATES)) ? _BUTTON_("upgrade package") (p->has(PACKAGE_INSTALLED) && !p->has(PACKAGE_ACT_REMOVE) && !p->has(PACKAGE_UPDATES));
: _BUTTON_("reinstall package")); }) &&
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"));
break; break;
case ID_REMOVE: case ID_REMOVE:
w->SetValue(package && package->has(PACKAGE_ACT_REMOVE | where)); w->SetValue(
w->Enable (package && package->can(PACKAGE_ACT_REMOVE | where)); package_list->allSelectedPackages([&](const InstallablePackageP& p) {
//w->SetLabel(package && package->... ? _BUTTON_("remove group") : _BUTTON_("remove package")); return p->has(PACKAGE_ACT_REMOVE | where) ||
(!p->has(PACKAGE_INSTALLED) && !p->has(PACKAGE_ACT_INSTALL));
}) &&
package_list->anySelectedPackage([&](const InstallablePackageP& p) {
return p->has(PACKAGE_ACT_REMOVE | where);
})
);
w->Enable(
package_list->anySelectedPackage([&](const InstallablePackageP& p) {
return p->can(PACKAGE_ACT_REMOVE | where);
})
);
w->SetLabel(is_group ? _BUTTON_("remove group") :
_BUTTON_("remove package"));
break; break;
} }
// TODO: change labels to _BUTTON_("install group"), _BUTTON_("remove group"), _BUTTON_("upgrade group")
} }
void PackagesWindow::onIdle(wxIdleEvent& ev) { void PackagesWindow::onIdle(wxIdleEvent& ev) {
@@ -409,12 +438,17 @@ bool PackagesWindow::checkInstallerList(bool refresh) {
// refresh // refresh
if (refresh) { if (refresh) {
package_list->rebuild(); package_list->rebuild();
package_info->setPackage(package = package_list->getSelection()); package_info->setPackage(package = package_list->getSelectedPackage());
UpdateWindowUI(wxUPDATE_UI_RECURSE); UpdateWindowUI(wxUPDATE_UI_RECURSE);
} }
return true; return true;
} }
void PackagesWindow::sendEvent() {
wxCommandEvent ev(EVENT_PACKAGE_LIST_CHANGED, GetId());
wxPostEvent(GetParent(), ev);
}
BEGIN_EVENT_TABLE(PackagesWindow, wxDialog) BEGIN_EVENT_TABLE(PackagesWindow, wxDialog)
EVT_LISTBOX (ID_PACKAGE_LIST, PackagesWindow::onPackageSelect) EVT_LISTBOX (ID_PACKAGE_LIST, PackagesWindow::onPackageSelect)
EVT_TOGGLEBUTTON(ID_KEEP, PackagesWindow::onActionChange) EVT_TOGGLEBUTTON(ID_KEEP, PackagesWindow::onActionChange)
+2
View File
@@ -51,5 +51,7 @@ private:
/// Check whether we have downloaded the list of installers /// Check whether we have downloaded the list of installers
/** If the download is (partially) complete, update the installable_packages list */ /** If the download is (partially) complete, update the installable_packages list */
bool checkInstallerList(bool refresh = true); bool checkInstallerList(bool refresh = true);
/// Notify that the package list has changed
void sendEvent();
}; };
+9 -6
View File
@@ -125,8 +125,8 @@ PreferencesWindow::PreferencesWindow(Window* parent)
s->Add(nb, 1, wxEXPAND | (wxALL & ~wxBOTTOM), 8); s->Add(nb, 1, wxEXPAND | (wxALL & ~wxBOTTOM), 8);
s->AddSpacer(4); s->AddSpacer(4);
s->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | (wxALL & ~wxTOP), 8); s->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | (wxALL & ~wxTOP), 8);
s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
} }
void PreferencesWindow::onOk(wxCommandEvent&) { void PreferencesWindow::onOk(wxCommandEvent&) {
@@ -177,7 +177,6 @@ GlobalPreferencesPage::GlobalPreferencesPage(Window* parent)
dark_mode->SetSelection((int)settings.dark_mode_type); dark_mode->SetSelection((int)settings.dark_mode_type);
// init sizer // init sizer
wxSizer* s = new wxBoxSizer(wxVERTICAL); wxSizer* s = new wxBoxSizer(wxVERTICAL);
s->SetSizeHints(this);
wxSizer* s2 = new wxStaticBoxSizer(wxVERTICAL, this, _LABEL_("language")); wxSizer* s2 = new wxStaticBoxSizer(wxVERTICAL, this, _LABEL_("language"));
s2->Add(new wxStaticText(this, wxID_ANY, _LABEL_("app language")), 0, wxALL, 4); s2->Add(new wxStaticText(this, wxID_ANY, _LABEL_("app language")), 0, wxALL, 4);
s2->Add(language, 0, wxEXPAND | (wxALL & ~wxTOP), 4); s2->Add(language, 0, wxEXPAND | (wxALL & ~wxTOP), 4);
@@ -191,6 +190,7 @@ GlobalPreferencesPage::GlobalPreferencesPage(Window* parent)
s4->Add(new wxStaticText(this, wxID_ANY, _HELP_( "app language")), 0, wxALL, 4); s4->Add(new wxStaticText(this, wxID_ANY, _HELP_( "app language")), 0, wxALL, 4);
s->Add(s4, 0, wxEXPAND | wxALL, 8); s->Add(s4, 0, wxEXPAND | wxALL, 8);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
} }
void GlobalPreferencesPage::store() { void GlobalPreferencesPage::store() {
@@ -243,8 +243,8 @@ DisplayPreferencesPage::DisplayPreferencesPage(Window* parent)
s3->Add(new wxStaticText(this, wxID_ANY, _LABEL_("percent of normal")),1, wxALL & ~wxRIGHT, 4); s3->Add(new wxStaticText(this, wxID_ANY, _LABEL_("percent of normal")),1, wxALL & ~wxRIGHT, 4);
s2->Add(s3, 0, wxEXPAND | wxALL, 4); s2->Add(s3, 0, wxEXPAND | wxALL, 4);
s->Add(s2, 0, wxEXPAND | wxALL, 8); s->Add(s2, 0, wxEXPAND | wxALL, 8);
s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
} }
void DisplayPreferencesPage::store() { void DisplayPreferencesPage::store() {
@@ -342,8 +342,8 @@ TransfersPreferencesPage::TransfersPreferencesPage(Window* parent) : Preferences
s->Add(s2, 0, wxEXPAND | wxALL, 8); s->Add(s2, 0, wxEXPAND | wxALL, 8);
s->Add(s5, 0, wxEXPAND | wxALL, 8); s->Add(s5, 0, wxEXPAND | wxALL, 8);
export_scale->SetFocus(); export_scale->SetFocus();
s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
} }
void TransfersPreferencesPage::store() { void TransfersPreferencesPage::store() {
@@ -375,8 +375,8 @@ DirsPreferencesPage::DirsPreferencesPage(Window* parent)
s3->Add(ab, 0, wxEXPAND); s3->Add(ab, 0, wxEXPAND);
s2->Add(s3, 0, wxEXPAND | (wxALL & ~wxTOP), 4); s2->Add(s3, 0, wxEXPAND | (wxALL & ~wxTOP), 4);
s->Add(s2, 0, wxEXPAND | wxALL, 8); s->Add(s2, 0, wxEXPAND | wxALL, 8);
s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
} }
void DirsPreferencesPage::store() { void DirsPreferencesPage::store() {
@@ -441,13 +441,16 @@ void UpdatePreferencesPage::store() {
} }
void UpdatePreferencesPage::onCheckUpdatesNow(wxCommandEvent&) { void UpdatePreferencesPage::onCheckUpdatesNow(wxCommandEvent&) {
downloadable_installers.shown_dialog = true;
downloadable_installers.check_updates_now(false); downloadable_installers.check_updates_now(false);
if (downloadable_installers.check_status == DownloadableInstallerList::CheckStatus::FAILED) { if (downloadable_installers.check_status == DownloadableInstallerList::CheckStatus::FAILED) {
wxMessageBox(_ERROR_("checking updates failed"), _TITLE_("update check"), wxICON_ERROR | wxOK); wxMessageBox(_ERROR_("checking updates failed"), _TITLE_("update check"), wxICON_ERROR | wxOK);
} else if (downloadable_installers.check_status == DownloadableInstallerList::CheckStatus::NOT_FOUND) { } else if (downloadable_installers.check_status == DownloadableInstallerList::CheckStatus::NOT_FOUND) {
wxMessageBox(_ERROR_("no updates"), _TITLE_("update check"), wxICON_INFORMATION | wxOK); wxMessageBox(_ERROR_("no updates"), _TITLE_("update check"), wxICON_INFORMATION | wxOK);
} else { } else {
(new PackagesWindow(GetParent()))->Show(); wxWindow* set_window = this;
while (set_window->GetParent()) set_window = set_window->GetParent();
(new PackagesWindow(set_window))->Show();
} }
} }
+1 -1
View File
@@ -37,7 +37,7 @@ void PrintJob::measure_cards() {
if (already_measured_cards.find(card) != already_measured_cards.end()) continue; if (already_measured_cards.find(card) != already_measured_cards.end()) continue;
already_measured_cards.emplace(card); already_measured_cards.emplace(card);
card_layouts.emplace_back(measure_card(card)); card_layouts.emplace_back(measure_card(card));
CardP other_face = card->getLinkedOtherFaceCard(cards); 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
if (other_face && already_measured_cards.find(other_face) == already_measured_cards.end()) { if (other_face && already_measured_cards.find(other_face) == already_measured_cards.end()) {
already_measured_cards.emplace(other_face); already_measured_cards.emplace(other_face);
card_layouts.emplace_back(measure_card(other_face)); card_layouts.emplace_back(measure_card(other_face));
+17 -3
View File
@@ -118,8 +118,8 @@ CardsPanel::CardsPanel(Window* parent, int id)
link_grid_4->Add(link_viewer_4, wxGBPosition(1, 0), wxGBSpan(1, 2)); link_grid_4->Add(link_viewer_4, wxGBPosition(1, 0), wxGBSpan(1, 2));
s->Add(s_left, 0, wxEXPAND | wxRIGHT, 2); s->Add(s_left, 0, wxEXPAND | wxRIGHT, 2);
s->Add(splitter, 1, wxEXPAND); s->Add(splitter, 1, wxEXPAND);
s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
// init menus // init menus
menuCard = new wxMenu(); menuCard = new wxMenu();
@@ -127,13 +127,14 @@ CardsPanel::CardsPanel(Window* parent, int id)
add_menu_item_tr(menuCard, ID_CARD_NEXT, nullptr, "next card"); add_menu_item_tr(menuCard, ID_CARD_NEXT, nullptr, "next card");
add_menu_item_tr(menuCard, ID_CARD_SEARCH, nullptr, "search cards"); add_menu_item_tr(menuCard, ID_CARD_SEARCH, nullptr, "search cards");
menuCard->AppendSeparator(); 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"); 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 // NOTE: space after "Del" prevents wx from making del an accellerator
// otherwise we delete a card when delete is pressed inside the editor // otherwise we delete a card when delete is pressed inside the editor
// Adding a space never hurts, please keep it just to be safe. // 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_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(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_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_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")); add_menu_item(menuCard, ID_CARD_AND_LINK_COPY, "card_copy", _MENU_("copy card and links") + _(" "), _HELP_("copy card and links"));
@@ -255,7 +256,7 @@ void CardsPanel::onChangeSet() {
insertManyCardsMenu->SetSubMenu(makeAddCardsSubmenu(false)); insertManyCardsMenu->SetSubMenu(makeAddCardsSubmenu(false));
// re-add the menu // re-add the menu
menuCard->Remove(ID_CARD_ADD_MULT); menuCard->Remove(ID_CARD_ADD_MULT);
((wxMenu*)menuCard)->Insert(4,insertManyCardsMenu); // HACK: the position is hardcoded ((wxMenu*)menuCard)->Insert(6,insertManyCardsMenu); // HACK: the position is hardcoded
// also for the toolbar dropdown menu // also for the toolbar dropdown menu
if (toolAddCard) { if (toolAddCard) {
// Originally this was using the menu directly, but there are compatibility issues apparently. // Originally this was using the menu directly, but there are compatibility issues apparently.
@@ -270,6 +271,7 @@ wxMenu* CardsPanel::makeAddCardsSubmenu(bool add_single_card_option) {
if (add_single_card_option) { if (add_single_card_option) {
cards_scripts_menu = new wxMenu(); 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, "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(); cards_scripts_menu->AppendSeparator();
} }
// create menu for add_cards_scripts // create menu for add_cards_scripts
@@ -435,6 +437,17 @@ void CardsPanel::onCommand(int id) {
case ID_CARD_ADD: case ID_CARD_ADD:
set->actions.addAction(make_unique<AddCardAction>(*set)); set->actions.addAction(make_unique<AddCardAction>(*set));
break; 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: case ID_CARD_ADD_CSV:
card_list->doAddCSV(); card_list->doAddCSV();
break; break;
@@ -656,6 +669,7 @@ CardP CardsPanel::selectedCard() const {
void CardsPanel::selectCard(const CardP& card) { 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); card_list->setCard(card);
editor->setCard(card); editor->setCard(card);
+12 -3
View File
@@ -14,6 +14,7 @@
#include <util/window_id.hpp> #include <util/window_id.hpp>
#include <data/stylesheet.hpp> #include <data/stylesheet.hpp>
#include <data/card.hpp> #include <data/card.hpp>
#include <script/functions/json.hpp>
#include <wx/splitter.h> #include <wx/splitter.h>
#include <wx/dcbuffer.h> #include <wx/dcbuffer.h>
#include <wx/clipbrd.h> #include <wx/clipbrd.h>
@@ -107,6 +108,7 @@ public:
} else { } else {
ok = wxTheClipboard->SetData(new wxTextDataObject(msg.text)); ok = wxTheClipboard->SetData(new wxTextDataObject(msg.text));
} }
wxTheClipboard->Flush();
wxTheClipboard->Close(); wxTheClipboard->Close();
return ok; return ok;
} }
@@ -513,8 +515,8 @@ ConsolePanel::ConsolePanel(Window* parent, int id)
// init sizer // init sizer
wxSizer* s = new wxBoxSizer(wxVERTICAL); wxSizer* s = new wxBoxSizer(wxVERTICAL);
s->Add(splitter, 1, wxEXPAND); s->Add(splitter, 1, wxEXPAND);
s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
// init menus // init menus
menuConsole = new wxMenu(); menuConsole = new wxMenu();
@@ -623,7 +625,7 @@ void ConsolePanel::exec(String const& command) {
// type of result // type of result
ScriptType type = result->type(); ScriptType type = result->type();
if (type == SCRIPT_IMAGE) { if (type == SCRIPT_IMAGE) {
GeneratedImage::Options options(0,0, set->stylesheet.get(), set.get()); GeneratedImage::Options options(0,0, card->stylesheet ? card->stylesheet.get() : set->stylesheet.get(), set.get());
wxImage image = result->toImage()->generate(options); wxImage image = result->toImage()->generate(options);
message->bitmap = wxBitmap(image); message->bitmap = wxBitmap(image);
} else if (type == SCRIPT_COLOR) { } else if (type == SCRIPT_COLOR) {
@@ -634,7 +636,14 @@ void ConsolePanel::exec(String const& command) {
set_alpha(image, color.Alpha() / 255.0); set_alpha(image, color.Alpha() / 255.0);
message->bitmap = wxBitmap(image); message->bitmap = wxBitmap(image);
} else { } else {
message->text = result->toCode(); try {
boost::json::value jresult = mse_to_json(result, set.get(), true);
if (jresult.is_null()) message->text = result->toCode();
else message->text = json_pretty_print(jresult);
}
catch (...) {
message->text = result->toCode();
}
} }
messages->add_message(message); messages->add_message(message);
} catch (ScriptError const& e) { } catch (ScriptError const& e) {
+20 -17
View File
@@ -60,29 +60,32 @@ void KeywordsPanel::initControls() {
sp = new wxBoxSizer(wxVERTICAL); sp = new wxBoxSizer(wxVERTICAL);
sp->Add(fixed, 0, wxEXPAND); sp->Show(fixed,false); sp->Add(fixed, 0, wxEXPAND); sp->Show(fixed,false);
wxSizer* s1 = new wxBoxSizer(wxVERTICAL); wxSizer* s1 = new wxBoxSizer(wxVERTICAL);
s1->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("keyword")+_(":")), 0, wxTOP, 2); s1->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("keyword")+_(":")), 0, wxTOP | wxLEFT, 4);
s1->Add(keyword, 1, wxEXPAND | wxTOP, 2); s1->Add(keyword, 0, wxEXPAND | wxTOP | wxLEFT, 4);
s1->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("mode")+_(":")), 0, wxTOP, 2);
s1->Add(mode, 0, wxEXPAND | wxTOP, 2);
sp->Add(s1, 0, wxEXPAND | wxRIGHT, 4); sp->Add(s1, 0, wxEXPAND | wxRIGHT, 4);
sp->Add(new wxStaticLine(panel), 0, wxEXPAND | wxTOP | wxBOTTOM, 8); sp->Add(new wxStaticLine(panel), 0, wxEXPAND | wxTOP | wxBOTTOM, 16);
wxSizer* s9 = new wxBoxSizer(wxVERTICAL);
s9->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("mode")+_(":")), 0, wxTOP | wxLEFT, 4);
s9->Add(mode, 0, wxEXPAND | wxTOP | wxLEFT, 4);
sp->Add(s9, 0, wxEXPAND | wxRIGHT, 4);
sp->Add(new wxStaticLine(panel), 0, wxEXPAND | wxTOP | wxBOTTOM, 16);
wxSizer* s2 = new wxBoxSizer(wxVERTICAL); wxSizer* s2 = new wxBoxSizer(wxVERTICAL);
s2->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("match")+_(":")), 0); s2->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("match")+_(":")), 0, wxTOP | wxLEFT, 4);
s2->Add(match, 1, wxEXPAND | wxTOP, 2); s2->Add(match, 0, wxEXPAND | wxTOP | wxLEFT, 4);
s2->Add(add_param, 0, wxALIGN_LEFT | wxTOP, 2); s2->Add(add_param, 0, wxALIGN_LEFT | wxTOP | wxLEFT, 4);
sp->Add(s2, 0, wxEXPAND | wxRIGHT, 4); sp->Add(s2, 0, wxEXPAND | wxRIGHT, 4);
sp->Add(new wxStaticLine(panel), 0, wxEXPAND | wxTOP | wxBOTTOM, 8); sp->Add(new wxStaticLine(panel), 0, wxEXPAND | wxTOP | wxBOTTOM, 16);
wxSizer* s3 = new wxBoxSizer(wxVERTICAL); wxSizer* s3 = new wxBoxSizer(wxVERTICAL);
s3->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("reminder")+_(":")), 0); s3->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("reminder")+_(":")), 0, wxTOP | wxLEFT, 4);
s3->Add(reminder, 1, wxEXPAND | wxTOP, 2); s3->Add(reminder, 1, wxEXPAND | wxTOP | wxLEFT, 4);
s3->Add(ref_param, 0, wxALIGN_LEFT | wxTOP, 2); s3->Add(ref_param, 0, wxALIGN_LEFT | wxTOP | wxLEFT, 4);
s3->Add(errors, 0, wxEXPAND | wxTOP, 4); s3->Add(errors, 0, wxEXPAND | wxTOP | wxLEFT, 4);
//s3->Add(new wxStaticText(panel, wxID_ANY, _("Example:")), 0, wxTOP, 6); //s3->Add(new wxStaticText(panel, wxID_ANY, _("Example:")), 0, wxTOP, 6);
sp->Add(s3, 1, wxEXPAND | wxRIGHT, 4); sp->Add(s3, 1, wxEXPAND | wxRIGHT, 4);
sp->Add(new wxStaticLine(panel), 0, wxEXPAND | wxTOP | wxBOTTOM, 8); sp->Add(new wxStaticLine(panel), 0, wxEXPAND | wxTOP | wxBOTTOM, 16);
wxSizer* s4 = new wxBoxSizer(wxVERTICAL); wxSizer* s4 = new wxBoxSizer(wxVERTICAL);
s4->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("rules")+_(":")), 0); s4->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("rules")+_(":")), 0, wxTOP | wxLEFT, 4);
s4->Add(rules, 1, wxEXPAND | wxTOP, 2); s4->Add(rules, 1, wxEXPAND | wxTOP | wxLEFT, 4);
sp->Add(s4, 1, wxEXPAND | wxRIGHT, 4); sp->Add(s4, 1, wxEXPAND | wxRIGHT, 4);
panel->SetSizer(sp); panel->SetSizer(sp);
// init splitter // init splitter
@@ -92,8 +95,8 @@ void KeywordsPanel::initControls() {
// init sizer // init sizer
wxSizer* s = new wxBoxSizer(wxHORIZONTAL); wxSizer* s = new wxBoxSizer(wxHORIZONTAL);
s->Add(splitter, 1, wxEXPAND); s->Add(splitter, 1, wxEXPAND);
s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
//s->Add(new wxStaticText(this, wxID_ANY, _("Sorry, no keywords for now"),wxDefaultPosition,wxDefaultSize,wxALIGN_CENTER), 1, wxALIGN_CENTER); // TODO: Remove //s->Add(new wxStaticText(this, wxID_ANY, _("Sorry, no keywords for now"),wxDefaultPosition,wxDefaultSize,wxALIGN_CENTER), 1, wxALIGN_CENTER); // TODO: Remove
/* wxSizer* s2 = new wxBoxSizer(wxVERTICAL); /* wxSizer* s2 = new wxBoxSizer(wxVERTICAL);
+2 -1
View File
@@ -24,8 +24,9 @@ class SetWindowPanel : public wxPanel, public SetView {
public: public:
SetWindowPanel(Window* parent, int id, bool autoTabbing = true); SetWindowPanel(Window* parent, int id, bool autoTabbing = true);
/// We will probably want to respond to set changes /// We will probably want to respond to set changes or package list changes
virtual void onSetChange() {} virtual void onSetChange() {}
virtual void onPackageListChange() {}
// // --------------------------------------------------- : Meta information // // --------------------------------------------------- : Meta information
// //
+2 -2
View File
@@ -301,8 +301,8 @@ CustomPackDialog::CustomPackDialog(Window* parent, const SetP& set, const PackTy
totals->setGame(set->game); totals->setGame(set->game);
updateTotals(); updateTotals();
// set sizer // set sizer
s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
} }
void CustomPackDialog::updateTotals() { void CustomPackDialog::updateTotals() {
@@ -417,8 +417,8 @@ void RandomPackPanel::initControls() {
s2->Add(s3, 0, wxEXPAND | (wxALL & ~wxTOP), 4); s2->Add(s3, 0, wxEXPAND | (wxALL & ~wxTOP), 4);
s2->Add(card_list, 1, wxEXPAND); s2->Add(card_list, 1, wxEXPAND);
s->Add(s2, 1, wxEXPAND, 8); s->Add(s2, 1, wxEXPAND, 8);
s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
} }
RandomPackPanel::~RandomPackPanel() { RandomPackPanel::~RandomPackPanel() {
+1 -1
View File
@@ -22,8 +22,8 @@ SetInfoPanel::SetInfoPanel(Window* parent, int id)
// init sizer // init sizer
wxSizer* s = new wxBoxSizer(wxVERTICAL); wxSizer* s = new wxBoxSizer(wxVERTICAL);
s->Add(editor, 1, wxEXPAND, 2); s->Add(editor, 1, wxEXPAND, 2);
s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
} }
void SetInfoPanel::onChangeSet() { void SetInfoPanel::onChangeSet() {
+1 -1
View File
@@ -330,8 +330,8 @@ void StatsPanel::initControls() {
s->Add(categories, 0, wxEXPAND | wxRIGHT, 2); s->Add(categories, 0, wxEXPAND | wxRIGHT, 2);
#endif #endif
s->Add(splitter, 1, wxEXPAND); s->Add(splitter, 1, wxEXPAND);
s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
// init menu // init menu
menuGraph = new wxMenu(); menuGraph = new wxMenu();
+21 -10
View File
@@ -55,8 +55,8 @@ void StylePanel::initControls() {
s4->Add(editor, 2, wxEXPAND, 0); s4->Add(editor, 2, wxEXPAND, 0);
s2->Add(s4, 1, wxEXPAND | wxALL, 2); s2->Add(s4, 1, wxEXPAND | wxALL, 2);
s->Add(s2, 1, wxEXPAND, 8); s->Add(s2, 1, wxEXPAND, 8);
s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
s->SetSizeHints(this);
} }
void StylePanel::initUI(wxToolBar* tb, wxMenuBar* mb) { void StylePanel::initUI(wxToolBar* tb, wxMenuBar* mb) {
@@ -95,7 +95,7 @@ bool StylePanel::Layout() {
void StylePanel::onChangeSet() { void StylePanel::onChangeSet() {
if (!isInitialized()) return; if (!isInitialized()) return;
list->showData<StyleSheet>(set->game->name() + _("-*")); list->showData<StyleSheet>(set->game->name() + _("*"));
list->select(set->stylesheet->name(), false); list->select(set->stylesheet->name(), false);
editor->setSet(set); editor->setSet(set);
preview->setSet(set); preview->setSet(set);
@@ -103,6 +103,24 @@ void StylePanel::onChangeSet() {
use_for_all->Enable(false); use_for_all->Enable(false);
} }
void StylePanel::onPackageListChange() {
if (!isInitialized()) return;
if (!list) return;
list->showData<StyleSheet>(set->game->name() + _("*"));
onFilterChange();
}
void StylePanel::onFilterChange() {
if (list->hasSelection()) {
StyleSheetP existingStylesheetSelection = list->getSelection<StyleSheet>(false);
list->setFilter(stylesheet_filter->getFilter<PackageData>());
list->select(existingStylesheetSelection->name());
}
else {
list->setFilter(stylesheet_filter->getFilter<PackageData>());
}
}
void StylePanel::onAction(const Action& action, bool undone) { void StylePanel::onAction(const Action& action, bool undone) {
if (!isInitialized()) return; if (!isInitialized()) return;
TYPE_CASE_(action, ChangeSetStyleAction) { TYPE_CASE_(action, ChangeSetStyleAction) {
@@ -139,14 +157,7 @@ void StylePanel::onAction(const Action& action, bool undone) {
} }
void StylePanel::onStylesheetFilterUpdate(wxCommandEvent&) { void StylePanel::onStylesheetFilterUpdate(wxCommandEvent&) {
if (list->hasSelection()) { onFilterChange();
StyleSheetP existingStylesheetSelection = list->getSelection<StyleSheet>(false);
list->setFilter(stylesheet_filter->getFilter<PackageData>());
list->select(existingStylesheetSelection->name());
}
else {
list->setFilter(stylesheet_filter->getFilter<PackageData>());
}
} }
// ----------------------------------------------------------------------------- : Selection // ----------------------------------------------------------------------------- : Selection

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