Editor enhancements (#8903)

Map/Scenario Editor

* Rename Load Map to Load Map/Scenario (since it can load both), Edit Scenario to Edit Scenario Settings, Save Map to just Save.
* Rearrange menu order
* Add icon for the preferences menu item (used the preexisting settings.png icon)
* Open folder correctly at Add-on's scenario directory instead of editor/scenarios. (#8910)
* Show Save Scenario As only for Scenarios
* Use the settings.png icon for Preferences menu item
* Add functionality to "Loyal" checkbox (Unit tool -> Place unit -> Right click menu) (#8445)
* Show warning when maps are saved in scenarios folder or vice versa (#8911)
* Unit List moved to Units menu from File menu to reduce some pressure from the latter.
* Status Table menu item disabled since it does nothing. (Should be reenabled once the functionality has been added.)
* Improve reload functionality in Editor (F5). Reload happens directly from memory and no temp files are needed. Also, the undo/redo stacks will be preserved. (#9024)

Time Schedule Editor

* Browse buttons now set wesnoth style paths instead of just pasting the absolute path returned by the file dialog
* Change text boxes from inactive to uneditable.
* Code generation improvements
* Add copyright notice to tod_new_schedule
* Confirmation messages
* Preview buttons for image and sound files and new icons for the preview button (2 sets : preview image and preview sound)

Unit Type Editor
 * Confirmation messages
 * New icons for the preview button (2 sets : preview image and preview sound)

Add-on menu
 * Two new menu entries for (1) opening the Add-on selection dialog, (2) opening the folder corresponding to the Add-on
The open add-on folder option shows a GUI2 file dialog at the add-on's folder which can be used to open any file. If it is a loadable map/scenario it will be opened in the editor, otherwise the OS's default application for that file will be opened.

File Dialog
 * Redesigned with new icons
 * New Open External button that opens selected file/folder in the platform's default application (independently of what pressing Open would do). This could be used to quickly open a folder or preview the file before actually selecting it.
 * Extension checking and filename validation. (See #8911)
This commit is contained in:
Subhraman Sarkar 2024-06-29 21:56:54 +05:30 committed by GitHub
parent 28a6a2a8b1
commit 103b80ff01
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
41 changed files with 1175 additions and 826 deletions

View file

@ -17736,6 +17736,13 @@ Date,File,License,Author - Real Name(other name);Real Name(other name);etc,Notes
2013/05/26,images/icons/action/playlist_30-active.png,GNU GPL v2+,Emilien Rotival(LordBob),,,74fd5c0b4927aafc27e79c8a360fe2c8
2013/05/26,images/icons/action/playlist_30-pressed.png,GNU GPL v2+,Emilien Rotival(LordBob),,,4a4338bcdcd23b78ea227461c68fc867
2013/05/26,images/icons/action/playlist_30.png,GNU GPL v2+,Emilien Rotival(LordBob),,,d719535714ed129c56133c2a0d3cd704
2024/05/24,images/icons/action/preferences_25.png,GNU GPL v2+,Emilien Rotival(LordBob),"same as settings.png, scaled down",,6a827ee3ad77fd60b17e4ea7167d7907
2024/05/23,images/icons/action/preview_25-active.png,GNU GPL v2+,Subhraman Sarkar(babaissarkar),,,6ad340e7d910c9b0fa31ce79e09164f1
2024/05/24,images/icons/action/preview_25-pressed.png,GNU GPL v2+,Subhraman Sarkar(babaissarkar),,,f93f8e433440defa9b6743593c122ead
2024/05/25,images/icons/action/preview_25.png,GNU GPL v2+,Subhraman Sarkar(babaissarkar),,,a157e05242054558882f3c778e04717e
2024/05/26,images/icons/action/preview_30-active.png,GNU GPL v2+,Subhraman Sarkar(babaissarkar),,,3e92dd9e71fc3eb6f4c443960719eaec
2024/05/27,images/icons/action/preview_30-pressed.png,GNU GPL v2+,Subhraman Sarkar(babaissarkar),,,11fa82232a9564c68f3847a4197f1df9
2024/05/28,images/icons/action/preview_30.png,GNU GPL v2+,Subhraman Sarkar(babaissarkar),,,aaa5307d0142806fcdd108c75bfe8860
2013/04/29,images/icons/action/redo_25-active.png,GNU GPL v2+,Emilien Rotival(LordBob),,,b7643aaf484e4ea98ee362f3b1b33915
2013/04/29,images/icons/action/redo_25-pressed.png,GNU GPL v2+,Emilien Rotival(LordBob),,,2d71a8c4d3ea72a9dc2149e5d22437c2
2013/04/29,images/icons/action/redo_25.png,GNU GPL v2+,Emilien Rotival(LordBob),,,a4d057572a76752b3d40e0bc63228f16
@ -18322,7 +18329,8 @@ Date,File,License,Author - Real Name(other name);Real Name(other name);etc,Notes
2011/03/11,images/misc/ellipse-selected-top.png,GNU GPL v2+,Jordà Polo(ettin);Lari Nieminen(zookeeper),,,383c573e6b6eb97e3d09ea97d63107e1
2011/03/11,images/misc/ellipse-top.png,GNU GPL v2+,Jordà Polo(ettin);Lari Nieminen(zookeeper),,,914b3908e00ab55071bde61dce55a6e6
2011/03/11,images/misc/eye.png,GNU GPL v2+,David White(dave),,,5e56c4e45341c3915664ca4f0c096897
2019/01/01,images/misc/folder-bookmark-icon.png,GNU GPL v2+,Emilien Rotival(LordBob),,,59a3279e2a6326f61b2f35531495d25e
2024/05/27,images/misc/file.png,GNU GPL v2+,Subhraman Sarkar(babaissarkar),,,edbfcfc60063ab4f5bfc2ccd09c4c7bd
2024/05/27,images/misc/folder-bookmark-icon.png,GNU GPL v2+,Subhraman Sarkar(babaissarkar);Emilien Rotival(LordBob),,,d325820e7532a93fbd76e230bbecc00b
2019/01/01,images/misc/folder-icon.png,GNU GPL v2+,Emilien Rotival(LordBob),,,2f646c254de628f5c388ce330d22918d
2011/03/11,images/misc/font8x8.png,GNU GPL v2+,unknown,,,f1b9efcedc4c8f5f46c890036469a538
2011/03/27,images/misc/hidden.png,GNU GPL v2+,Ali El Gariani(alink),,,508dc64614fd0b5d5abc492c39a4926d

Can't render this file because it is too large.

View file

@ -468,7 +468,15 @@
"preview"
"Preview button"
"buttons/button_square/button_square_25"
"icons/action/zoomdefault_25"
"icons/action/preview_25"
()
}
{_GUI_DEFINITION
"play"
"Play button"
"buttons/button_square/button_square_25"
"icons/action/play_25"
()
}

View file

@ -3,7 +3,7 @@
### Definition of the custom tod window in the editor.
###
#define _GUI_DATA_PATH_ENTRY ID_STEM LABEL
#define _GUI_DATA_PATH_ENTRY ID_STEM LABEL PREVIEW_BUTTON
[row]
grow_factor = 0
@ -33,9 +33,12 @@
[text_box]
id = "path_" + {ID_STEM}
definition = "default"
editable = false
[/text_box]
[/column]
{PREVIEW_BUTTON}
[column]
grow_factor = 0
@ -72,6 +75,42 @@
[/row]
#enddef
#define _GUI_DATA_PATH_ENTRY_IMAGE ID_STEM LABEL
{_GUI_DATA_PATH_ENTRY {ID_STEM} {LABEL} (
[column]
grow_factor = 0
border = "all"
border_size = 5
horizontal_grow = true
[button]
id = "preview_" + {ID_STEM}
definition = "preview"
tooltip = _ "Preview image"
[/button]
[/column]
)}
#enddef
#define _GUI_DATA_PATH_ENTRY_SOUND ID_STEM LABEL
{_GUI_DATA_PATH_ENTRY {ID_STEM} {LABEL} (
[column]
grow_factor = 0
border = "all"
border_size = 5
horizontal_grow = true
[button]
id = "preview_" + {ID_STEM}
definition = "play"
tooltip = _ "Play sound"
[/button]
[/column]
)}
#enddef
#define _GUI_COLOR_SLIDER _ID _LABEL
[row]
grow_factor = 0
@ -310,9 +349,9 @@
[grid]
{_GUI_DATA_PATH_ENTRY "image" ( _ "Image:")}
{_GUI_DATA_PATH_ENTRY "mask" ( _ "Mask:")}
{_GUI_DATA_PATH_ENTRY "sound" ( _ "Sound:")}
{_GUI_DATA_PATH_ENTRY_IMAGE "image" ( _ "Image:")}
{_GUI_DATA_PATH_ENTRY_IMAGE "mask" ( _ "Mask:")}
{_GUI_DATA_PATH_ENTRY_SOUND "sound" ( _ "Sound:")}
[/grid]
@ -454,8 +493,9 @@
horizontal_alignment = "right"
[button]
id = "preview"
id = "preview_color"
definition = "preview"
tooltip = _ "Preview color changes on map"
[/button]
[/column]

View file

@ -124,27 +124,14 @@
### Main Stats page
[row]
[column]
[grid]
[row]
[column]
[panel]
definition="box_display"
horizontal_alignment = left
vertical_alignment = top
[panel]
definition="box_display"
[grid]
[row]
[column]
[grid]
id="grid_stats"
[row]
[column]
border = "all"
border_size = 5
horizontal_alignment = "left"
[label]
id = "title"
definition = "title"
label = _ "Stats"
[/label]
[/column]
{_GUI_INFO_TAB_PADDING}
[/row]
[row]
[column]
grow_factor = 0
@ -340,7 +327,8 @@
border = "all"
border_size = 5
horizontal_alignment = "left"
horizontal_grow = true
vertical_grow = true
[scroll_text]
id = "desc_box"
@ -373,7 +361,7 @@
definition = "default"
[/menu_button]
[/column]
[/row]
[/row]
[row]
[column]
@ -495,10 +483,10 @@
[/column]
[/row]
[/grid]
[/panel]
[/column]
[/row]
[/grid]
[/column]
[/row]
[/grid]
[/panel]
[/column]
[column]
@ -518,6 +506,8 @@
### Attacks
[row]
[column]
horizontal_alignment = left
vertical_alignment = top
[panel]
definition="box_display"
[grid]
@ -821,29 +811,14 @@
#define _GUI_ADVANCED_PAGE
### Advanced stats
[row]
[column]
horizontal_alignment = "left"
horizontal_alignment = left
vertical_alignment = top
[panel]
definition="box_display"
[grid]
id="grid_atk"
[row]
[column]
border = "all"
border_size = 5
horizontal_alignment = "left"
[label]
id = "title"
definition = "title"
label = _ "Advanced"
[/label]
[/column]
{_GUI_INFO_TAB_PADDING}
[/row]
id="grid_adv"
{_GUI_DATA_PATH_ENTRY_2_COL small_profile_image (_ "Small Profile")}
@ -1118,32 +1093,32 @@
#enddef
#define _GUI_WML_PAGE
[row]
[column]
horizontal_grow = true
vertical_grow = true
[panel]
definition="box_display"
[grid]
id="grid_wml"
[row]
[column]
border = "all"
border_size = 5
horizontal_grow = true
vertical_grow = true
[scroll_text]
id = "wml_view"
definition = "verbatim"
editable = false
[/scroll_text]
[/column]
[/row]
[/grid]
[/panel]
[/column]
[/row]
[row]
[column]
horizontal_grow = true
vertical_grow = true
[panel]
definition="box_display"
[grid]
id="grid_wml"
[row]
[column]
border = "all"
border_size = 5
horizontal_grow = true
vertical_grow = true
[scroll_text]
id = "wml_view"
definition = "verbatim"
editable = false
[/scroll_text]
[/column]
[/row]
[/grid]
[/panel]
[/column]
[/row]
#enddef
[window]
@ -1153,10 +1128,6 @@
[resolution]
definition = "default"
automatic_placement = true
vertical_placement = "center"
horizontal_placement = "center"
[tooltip]
id = "tooltip"
[/tooltip]
@ -1184,126 +1155,63 @@
id="main_grid"
[row]
[column]
border=all
border_size=5
vertical_alignment=top
horizontal_alignment=left
[label]
definition=title
label= _ "New Unit Type"
[/label]
[/column]
[/row]
[row]
[column]
[spacer]
height = 5
[/spacer]
[/column]
[/row]
[row]
[column]
vertical_alignment=top
[grid]
id="row_grid"
[row]
[column]
[listbox]
id="tabs"
[list_definition]
[row]
[column]
[toggle_panel]
linked_group = "tabs"
[grid]
[row]
{_GUI_INFO_TAB_PADDING}
[column]
grow_factor = 1
border = all
border_size = 5
[image]
id = "tab_image"
[/image]
[/column]
[column]
grow_factor = 1
border = all
border_size = 5
[label]
id = "tab_label"
wrap = true
[/label]
[/column]
{_GUI_INFO_TAB_PADDING}
[/row]
[/grid]
[/toggle_panel]
[/column]
[/row]
[/list_definition]
[list_data]
[row]
[column]
[widget]
id = "tab_image"
label = "/data/core/images/units/human-loyalists/general.png"
[/widget]
[widget]
id = "tab_label"
label = _ "Main Stats"
[/widget]
[/column]
[/row]
[row]
[column]
[widget]
id = "tab_image"
label = "/data/core/images/attacks/rectangular-shield.png"
[/widget]
[widget]
id = "tab_label"
label = _ "Advanced"
[/widget]
[/column]
[/row]
[row]
[column]
[widget]
id = "tab_image"
label = "/data/core/images/attacks/sword-human.png"
[/widget]
[widget]
id = "tab_label"
label = _ "Attacks"
[/widget]
[/column]
[/row]
[row]
[column]
[widget]
id = "tab_image"
label = "/data/core/images/attacks/gaze.png"
[/widget]
[widget]
id = "tab_label"
label = _ "WML View"
[/widget]
[/column]
[/row]
[/list_data]
[/listbox]
[/column]
[column]
[stacked_widget]
id = "page"
definition = "default"
[layer]
{_GUI_MAIN_STATS_PAGE}
[/layer]
[layer]
{_GUI_ADVANCED_PAGE}
[/layer]
[layer]
{_GUI_ATTACK_PAGE}
[/layer]
[layer]
{_GUI_WML_PAGE}
[/layer]
[/stacked_widget]
vertical_alignment = top
[tab_container]
id = tabs
[tab]
name = _ "Main Stats"
image = "/data/core/images/units/human-loyalists/general.png"
[data]
{_GUI_MAIN_STATS_PAGE}
[/data]
[/tab]
[tab]
name = _ "Advanced"
image = "/data/core/images/attacks/rectangular-shield.png"
[data]
{_GUI_ADVANCED_PAGE}
[/data]
[/tab]
[tab]
name = _ "Attacks"
image = "/data/core/images/attacks/sword-human.png"
[data]
{_GUI_ATTACK_PAGE}
[/data]
[/tab]
[tab]
name = _ "WML View"
image = "/data/core/images/attacks/gaze.png"
[data]
{_GUI_WML_PAGE}
[/data]
[/tab]
[/tab_container]
[/column]
[/row]
[/grid]

View file

@ -11,7 +11,7 @@
[resolution]
definition = "default"
{GUI_WINDOW_FIXED_SIZE_CENTERED 700 750}
{GUI_WINDOW_FIXED_SIZE_CENTERED 750 650}
[linked_group]
id = "bookmark_icons"
@ -80,294 +80,6 @@
[/row]
[row]
grow_factor = 1
[column]
horizontal_grow = true
vertical_grow = true
[grid]
[row]
grow_factor = 0
[column]
grow_factor = 0
border = "all"
border_size = 5
horizontal_alignment = "left"
[label]
definition = "gold_small"
label = _ "Places"
[/label]
[/column]
[column]
grow_factor = 1
horizontal_grow = true
border = "all"
border_size = 5
[label]
id = "current_dir"
definition = "gold_small"
wrap = false
can_shrink = true
[/label]
[/column]
[/row]
[row]
grow_factor = 1
[column]
grow_factor = 0
horizontal_grow = true
vertical_grow = true
border = "all"
border_size = 5
[listbox]
id = "bookmarks"
definition = "default"
has_minimum = false
horizontal_scrollbar_mode = "never"
[list_definition]
[row]
[column]
vertical_grow = true
horizontal_grow = true
[toggle_panel]
definition = "default"
[grid]
[row]
[column]
grow_factor = 0
horizontal_alignment = "left"
border = "all"
border_size = 5
[image]
id = "icon"
definition = "default"
linked_group = "bookmark_icons"
label = "misc/folder-bookmark-icon.png"
[/image]
[/column]
[column]
grow_factor = 1
horizontal_grow = true
border = "all"
border_size = 5
[label]
id = "bookmark"
definition = "default"
linked_group = "bookmark_labels"
wrap = true
[/label]
[/column]
[/row]
[/grid]
[/toggle_panel]
[/column]
[/row]
[/list_definition]
[/listbox]
[/column]
[column]
grow_factor = 1
horizontal_grow = true
vertical_grow = true
border = "all"
border_size = 5
[listbox]
id = "filelist"
definition = "default"
[list_definition]
[row]
[column]
vertical_grow = true
horizontal_grow = true
[toggle_panel]
# Needed for double-click event handling!
id = "item_panel"
definition = "default"
[grid]
[row]
[column]
grow_factor = 0
horizontal_alignment = "left"
border = "all"
border_size = 5
[image]
id = "icon"
definition = "default"
linked_group = "fileview_icons"
[/image]
[/column]
[column]
grow_factor = 1
horizontal_grow = true
border = "all"
border_size = 5
[label]
id = "file"
definition = "default"
linked_group = "fileview_labels"
[/label]
[/column]
[/row]
[/grid]
[/toggle_panel]
[/column]
[/row]
[/list_definition]
[/listbox]
[/column]
[/row]
[row]
grow_factor = 0
[column]
horizontal_grow = true
[grid]
[row]
[column]
border = "all"
border_size = 5
horizontal_alignment = "left"
grow_factor = 1
[button]
id = "add_bookmark"
definition = "add"
tooltip = _ "Bookmarks the current folder"
[/button]
[/column]
[column]
border = "all"
border_size = 5
horizontal_alignment = "right"
[button]
id = "remove_bookmark"
definition = "delete"
tooltip = _ "Removes the current bookmark"
[/button]
[/column]
[/row]
[/grid]
[/column]
[column]
horizontal_grow = true
[grid]
[row]
[column]
border = "all"
border_size = 5
horizontal_alignment = "left"
grow_factor = 1
[button]
id = "delete_file"
#definition = "action_delete_file"
label = _ "Delete"
[/button]
[/column]
[column]
border = "all"
border_size = 5
horizontal_alignment = "right"
[button]
id = "new_dir"
definition = "default"
label = _ "New Folder"
[/button]
[/column]
[/row]
[/grid]
[/column]
[/row]
[/grid]
[/column]
[/row]
[row]
grow_factor = 0
@ -407,6 +119,366 @@
[/column]
[/row]
[row]
[column]
[spacer][/spacer]
[/column]
[column]
border = "left"
border_size = 5
horizontal_grow = true
[label]
id = "validation_msg"
definition = "default"
use_markup = true
wrap = false
[/label]
[/column]
[/row]
[/grid]
[/column]
[/row]
[row]
[column]
[spacer]
height = 10
[/spacer]
[/column]
[/row]
[row]
grow_factor = 1
[column]
horizontal_alignment = left
vertical_grow = true
[grid]
[row]
grow_factor = 0
[column]
grow_factor = 0
vertical_grow = true
[grid]
[row]
[column]
horizontal_alignment = left
vertical_alignment = top
[panel]
definition = box_display
[grid]
[row]
[column]
grow_factor = 0
border = top,left,right
border_size = 5
horizontal_alignment = "left"
[label]
definition = "gold_small"
label = _ "Places"
[/label]
[/column]
[/row]
[row]
[column]
border = bottom,left,right
border_size = 5
horizontal_grow = true
vertical_grow = true
[listbox]
id = "bookmarks"
definition = "default"
has_minimum = false
horizontal_scrollbar_mode = "never"
[list_definition]
[row]
[column]
vertical_grow = true
horizontal_grow = true
[toggle_panel]
definition = "default"
[grid]
[row]
[column]
grow_factor = 0
horizontal_alignment = "left"
border = "all"
border_size = 5
[image]
id = "icon"
definition = "default"
linked_group = "bookmark_icons"
label = "misc/folder-bookmark-icon.png"
[/image]
[/column]
[column]
grow_factor = 1
horizontal_grow = true
border = "all"
border_size = 5
[label]
id = "bookmark"
definition = "default"
linked_group = "bookmark_labels"
wrap = true
[/label]
[/column]
[/row]
[/grid]
[/toggle_panel]
[/column]
[/row]
[/list_definition]
[/listbox]
[/column]
[/row]
[row]
[column]
horizontal_alignment = left
[grid]
[row]
[column]
border = "all"
border_size = 5
horizontal_alignment = "left"
grow_factor = 1
[button]
id = "add_bookmark"
definition = add
tooltip = _ "Bookmarks the current folder"
[/button]
[/column]
[column]
border = "all"
border_size = 5
horizontal_alignment = "left"
[button]
id = "remove_bookmark"
definition = delete
tooltip = _ "Removes the current bookmark"
[/button]
[/column]
[/row]
[/grid]
[/column]
[/row]
[/grid]
[/panel]
[/column]
[/row]
[row]
[column]
horizontal_alignment = center
vertical_alignment = bottom
[grid]
[row]
[column]
border = "all"
border_size = 5
horizontal_alignment = "left"
[button]
id = "open_ext"
definition = "default"
label = _ "Open External"
tooltip = _ "Open selected using platform's default applications"
[/button]
[/column]
[/row]
[row]
[column]
border = "all"
border_size = 5
horizontal_alignment = "left"
[button]
id = "new_dir"
definition = "default"
label = _ "New Folder"
[/button]
[/column]
[/row]
[row]
[column]
border = "all"
border_size = 5
horizontal_alignment = "left"
grow_factor = 1
[button]
id = "delete_file"
label = _ "Delete"
[/button]
[/column]
[/row]
[/grid]
[/column]
[/row]
[/grid]
[/column]
[column]
[spacer]
width = 5
[/spacer]
[/column]
[column]
grow_factor = 0
vertical_grow = true
horizontal_grow = true
[panel]
definition = box_display
[grid]
[row]
[column]
vertical_alignment = top
[grid]
[row]
[column]
border = "top,right,bottom"
border_size = 5
[spacer]
width = 440
[/spacer]
[/column]
[/row]
[row]
[column]
horizontal_grow = true
vertical_alignment = top
border = "top,right,bottom"
border_size = 5
[label]
id = "current_dir"
definition = "gold_small"
wrap = false
can_shrink = true
[/label]
[/column]
[/row]
[row]
[column]
horizontal_grow = true
vertical_alignment = top
border = "top,right,bottom"
border_size = 5
[listbox]
id = "filelist"
definition = "default"
[list_definition]
[row]
[column]
vertical_grow = true
horizontal_grow = true
[toggle_panel]
# Needed for double-click event handling!
id = "item_panel"
definition = "default"
[grid]
[row]
[column]
grow_factor = 0
horizontal_alignment = "left"
border = "top,bottom"
border_size = 5
[image]
id = "icon"
definition = "default"
linked_group = "fileview_icons"
[/image]
[/column]
[column]
grow_factor = 1
horizontal_grow = true
border = "all"
border_size = 5
[label]
id = "file"
definition = "default"
linked_group = "fileview_labels"
[/label]
[/column]
[/row]
[/grid]
[/toggle_panel]
[/column]
[/row]
[/list_definition]
[/listbox]
[/column]
[/row]
[/grid]
[/column]
[/row]
[/grid]
[/panel]
[/column]
[/row]
[/grid]

View file

@ -36,7 +36,7 @@
[menu]
id=menu-editor-paste-context
is_context_menu=true
items=describeterrain,menu-unit-facing,editor-unit-toggle-loyal,editor-change-unitid,renameunit,describeunit,editor-deleteunit,editor-toggle-renameable,editor-toggle-canrecruit,editor-cut,editor-copy,editor-paste,editor-tool-select,editor-select-all,editor-select-inverse,editor-select-none,editor-clipboard-rotate-cw,editor-clipboard-rotate-ccw,editor-clipboard-flip-horizontal,editor-clipboard-flip-vertical,editor-selection-fill,editor-selection-rotate,editor-selection-flip,editor-selection-randomize,editor-save-area
items=describeterrain,editor-change-unitid,renameunit,describeunit,editor-deleteunit,menu-unit-facing,editor-unit-toggle-loyal,editor-toggle-renameable,editor-toggle-canrecruit,editor-cut,editor-copy,editor-paste,editor-tool-select,editor-select-all,editor-select-inverse,editor-select-none,editor-clipboard-rotate-cw,editor-clipboard-rotate-ccw,editor-clipboard-flip-horizontal,editor-clipboard-flip-vertical,editor-selection-fill,editor-selection-rotate,editor-selection-flip,editor-selection-randomize,editor-save-area
[/menu]
####### Menu Bar
@ -61,7 +61,7 @@
title= _ "File"
type=turbo
font_size=9
items=editor-scenario-edit,statustable,unitlist,editor-map-new,editor-scenario-new,editor-map-load,menu-editor-recent,editor-map-revert,editor-map-save,editor-map-save-as,editor-scenario-save-as,mapscreenshot,editor-map-save-all,preferences,help,editor-close-map,quit,quit-to-desktop
items=editor-map-new,editor-scenario-new,editor-scenario-edit,statustable,editor-map-load,menu-editor-recent,editor-map-revert,editor-map-save,editor-map-save-as,editor-scenario-save-as,mapscreenshot,editor-map-save-all,preferences,help,editor-close-map,quit,quit-to-desktop
ref=top-panel
rect="=,=+1,+100,+20"
xanchor=fixed
@ -109,7 +109,7 @@
id=menu-editor-addon
title= _ "Add-on"
image=button_menu/menu_button_copper_H20
items=editor-pbl, editor-addon-id
items=editor-pbl, editor-addon-id, editor-addon-select, editor-addon-open
rect="+0,=,+100,="
xanchor=fixed
yanchor=fixed
@ -140,7 +140,7 @@
id=menu-editor-unit
title= _ "Unit"
image=button_menu/menu_button_copper_H20
items=editor-edit-unit
items=unitlist,editor-edit-unit
rect="+0,=,+100,="
xanchor=fixed
yanchor=fixed

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 952 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 887 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 993 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 991 B

BIN
images/misc/file.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 659 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 B

After

Width:  |  Height:  |  Size: 4.8 KiB

View file

@ -17,6 +17,8 @@
#include "editor/map/context_manager.hpp"
#include "desktop/open.hpp"
#include "editor/action/action.hpp"
#include "editor/action/action_unit.hpp"
#include "editor/action/action_select.hpp"
@ -33,6 +35,7 @@
#include "gui/dialogs/editor/edit_unit.hpp"
#include "gui/dialogs/editor/custom_tod.hpp"
#include "gui/dialogs/editor/tod_new_schedule.hpp"
#include "gui/dialogs/file_dialog.hpp"
#include "gui/dialogs/message.hpp"
#include "gui/dialogs/preferences_dialog.hpp"
#include "gui/dialogs/transient_message.hpp"
@ -88,7 +91,6 @@ editor_controller::editor_controller(bool clear_id)
toolkit_.reset(new editor_toolkit(*gui_.get(), key_, game_config_, *context_manager_.get()));
help_manager_.reset(new help::help_manager(&game_config_));
context_manager_->locs_ = toolkit_->get_palette_manager()->location_palette_.get();
context_manager_->switch_context(0, true);
init_tods(game_config_);
init_music(game_config_);
get_current_map_context().set_starting_position_labels(gui());
@ -238,7 +240,7 @@ void editor_controller::custom_tods_dialog()
tod_manager& manager = *get_current_map_context().get_time_manager();
std::vector<time_of_day> prev_schedule = manager.times();
gui2::dialogs::custom_tod tod_dlg(manager.times(), manager.get_current_time());
gui2::dialogs::custom_tod tod_dlg(manager.times(), manager.get_current_time(), current_addon_id_);
/* Register callback to the dialog so that the map changes can be
* previewed in real time.
@ -251,12 +253,12 @@ void editor_controller::custom_tods_dialog()
tod_dlg.register_callback(update_func);
/* Autogenerate schedule id */
// TODO : sch_name should be translatable
std::int64_t current_millis = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
std::string sch_id = current_addon_id_+"-schedule";
std::string sch_name;
/* Set correct textdomain */
t_string sch_name("", "wesnoth-"+current_addon_id_);
// TODO : Needs better error handling
// TODO : Needs better error handling messages
/* Show dialog and update current schedule */
if(tod_dlg.show()) {
/* Save the new schedule */
@ -359,8 +361,12 @@ bool editor_controller::can_execute_command(const hotkey::ui_command& cmd) const
case HOTKEY_UNIT_LIST:
return !get_current_map_context().units().empty();
// TODO Disabling this for now until the functionality can be implemnted.
// See the status_table() method
case HOTKEY_STATUS_TABLE:
return !get_current_map_context().teams().empty();
//return !get_current_map_context().teams().empty();
return false;
/////////////////////////////
case HOTKEY_TERRAIN_DESCRIPTION:
return gui().mouseover_hex().valid();
@ -380,29 +386,33 @@ bool editor_controller::can_execute_command(const hotkey::ui_command& cmd) const
return (toolkit_->is_mouse_action_set(HOTKEY_EDITOR_TOOL_UNIT) &&
units.find(loc) != units.end());
}
case HOTKEY_UNDO:
case HOTKEY_EDITOR_PARTIAL_UNDO:
return get_current_map_context().can_undo();
case HOTKEY_REDO:
return get_current_map_context().can_redo();
case HOTKEY_EDITOR_PARTIAL_UNDO:
return get_current_map_context().can_undo();
case TITLE_SCREEN__RELOAD_WML:
case HOTKEY_QUIT_TO_DESKTOP:
case HOTKEY_EDITOR_MAP_NEW:
case HOTKEY_EDITOR_SCENARIO_NEW:
case HOTKEY_EDITOR_MAP_LOAD:
case HOTKEY_EDITOR_MAP_SAVE_AS:
case HOTKEY_EDITOR_SCENARIO_SAVE_AS:
return true;
// Only enable when editing a scenario
case HOTKEY_EDITOR_EDIT_UNIT:
case HOTKEY_EDITOR_CUSTOM_TODS:
case HOTKEY_EDITOR_SCENARIO_SAVE_AS:
return !get_current_map_context().is_pure_map();
case HOTKEY_EDITOR_PBL:
case HOTKEY_EDITOR_CHANGE_ADDON_ID:
case HOTKEY_EDITOR_SELECT_ADDON:
case HOTKEY_EDITOR_OPEN_ADDON:
return true;
case HOTKEY_EDITOR_AREA_ADD:
case HOTKEY_EDITOR_SIDE_NEW:
return !get_current_map_context().is_pure_map();
@ -802,7 +812,7 @@ bool editor_controller::do_execute_command(const hotkey::ui_command& cmd, bool p
quit_confirmation::quit_to_desktop();
return true;
case TITLE_SCREEN__RELOAD_WML:
context_manager_->save_all_maps(true);
context_manager_->save_contexts();
do_quit_ = true;
quit_mode_ = EXIT_RELOAD_DATA;
return true;
@ -837,27 +847,54 @@ bool editor_controller::do_execute_command(const hotkey::ui_command& cmd, bool p
return true;
case HOTKEY_EDITOR_PBL:
if(current_addon_id_ == "") {
current_addon_id_ = editor::initialize_addon();
context_manager_->set_addon_id(current_addon_id_);
}
initialize_addon_if_empty();
if(current_addon_id_ != "") {
if(!current_addon_id_.empty()) {
context_manager_->edit_pbl();
}
return true;
case HOTKEY_EDITOR_CHANGE_ADDON_ID:
if(current_addon_id_ == "") {
current_addon_id_ = editor::initialize_addon();
context_manager_->set_addon_id(current_addon_id_);
}
initialize_addon_if_empty();
if(current_addon_id_ != "") {
if(!current_addon_id_.empty()) {
context_manager_->change_addon_id();
}
return true;
case HOTKEY_EDITOR_SELECT_ADDON:
current_addon_id_ = editor::initialize_addon();
context_manager_->set_addon_id(current_addon_id_);
return true;
case HOTKEY_EDITOR_OPEN_ADDON:
{
initialize_addon_if_empty();
gui2::dialogs::file_dialog dlg;
dlg.set_title(_("Add-on Files"))
.set_path(filesystem::get_current_editor_dir(current_addon_id_));
if (dlg.show()) {
std::string filepath = dlg.path();
if (filepath.substr(filepath.size() - 4) == ".map"
|| filepath.substr(filepath.size() - 4) == ".cfg") {
// Open map or scenario
context_manager_->load_map(filepath, true);
} else {
// Open file using OS application for that format
if (desktop::open_object_is_supported()) {
desktop::open_object(filepath);
} else {
gui2::show_message("", _("Opening files is not supported, contact your packager"), gui2::dialogs::message::auto_close);
}
}
}
return true;
}
case HOTKEY_EDITOR_AREA_ADD:
add_area();
return true;
@ -884,6 +921,14 @@ bool editor_controller::do_execute_command(const hotkey::ui_command& cmd, bool p
un->anim_comp().set_standing();
}
return true;
case HOTKEY_EDITOR_UNIT_TOGGLE_LOYAL:
{
map_location loc = gui_->mouseover_hex();
const unit_map::unit_iterator un = get_current_map_context().units().find(loc);
bool loyal = un->loyal();
un->set_loyal(!loyal);
}
return true;
case HOTKEY_DELETE_UNIT:
{
map_location loc = gui_->mouseover_hex();
@ -994,12 +1039,9 @@ bool editor_controller::do_execute_command(const hotkey::ui_command& cmd, bool p
context_manager_->new_map_dialog();
return true;
case HOTKEY_EDITOR_SCENARIO_NEW:
if(current_addon_id_ == "") {
current_addon_id_ = editor::initialize_addon();
context_manager_->set_addon_id(current_addon_id_);
}
initialize_addon_if_empty();
if(current_addon_id_ != "") {
if(!current_addon_id_.empty()) {
context_manager_->new_scenario_dialog();
}
return true;
@ -1013,12 +1055,9 @@ bool editor_controller::do_execute_command(const hotkey::ui_command& cmd, bool p
context_manager_->save_map_as_dialog();
return true;
case HOTKEY_EDITOR_SCENARIO_SAVE_AS:
if(current_addon_id_ == "") {
current_addon_id_ = editor::initialize_addon();
context_manager_->set_addon_id(current_addon_id_);
}
initialize_addon_if_empty();
if(current_addon_id_ != "") {
if(!current_addon_id_.empty()) {
context_manager_->save_scenario_as_dialog();
}
return true;
@ -1109,6 +1148,13 @@ bool editor_controller::do_execute_command(const hotkey::ui_command& cmd, bool p
}
}
void editor_controller::initialize_addon_if_empty() {
if(current_addon_id_.empty()) {
current_addon_id_ = editor::initialize_addon();
}
context_manager_->set_addon_id(current_addon_id_);
}
void editor_controller::show_help()
{
help::show_help("..editor");

View file

@ -65,10 +65,7 @@ class editor_controller : public controller_base,
editor_controller& operator=(const editor_controller&) = delete;
/**
* The constructor. A initial map context can be specified here, the controller
* will assume ownership and delete the pointer during destruction, but changes
* to the map can be retrieved between the main loop's end and the controller's
* destruction.
* The constructor.
*/
editor_controller(bool clear_id);
@ -165,6 +162,9 @@ class editor_controller : public controller_base,
return context_manager_->get_map_context();
}
/** Initialize an addon if the addon id is empty */
void initialize_addon_if_empty();
protected:
/* controller_base overrides */
void process_keyup_event(const SDL_Event& event) override;

View file

@ -118,7 +118,7 @@ EXIT_STATUS start(bool clear_id, const std::string& filename, bool take_screensh
editor_controller editor(clear_id);
if (!filename.empty() && filesystem::file_exists (filename)) {
if (!filename.empty() && filesystem::file_exists(filename)) {
if (filesystem::is_directory(filename)) {
editor.context_manager_->set_default_dir(filename);
editor.context_manager_->load_map_dialog(true);
@ -126,8 +126,7 @@ EXIT_STATUS start(bool clear_id, const std::string& filename, bool take_screensh
editor.context_manager_->load_map(filename, false);
// HACK: this fixes an issue where the button overlays would be missing when
// the loaded map appears. Since we're gonna drop this ridiculous GUI1 drawing
// stuff in 1.15 I'm not going to waste time coming up with a better fix.
// the loaded map appears.
//
// Do note adding a redraw_everything call to context_manager::refresh_all also
// fixes the issue, but I'm pretty sure thats just because editor_controller::

View file

@ -52,12 +52,14 @@
#include <memory>
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
namespace editor {
namespace {
static std::vector<std::string> saved_windows_;
std::vector<std::unique_ptr<editor::map_context>> saved_contexts_;
int last_context_ = 0;
static const std::string get_menu_marker(const bool changed)
const std::string get_menu_marker(const bool changed)
{
std::ostringstream ss;
ss << "[<span ";
@ -70,11 +72,15 @@ static const std::string get_menu_marker(const bool changed)
return ss.str();
}
}
namespace editor {
context_manager::context_manager(editor_display& gui, const game_config_view& game_config, const std::string& addon_id)
: locs_(nullptr)
, gui_(gui)
, game_config_(game_config)
, default_dir_(prefs::get().default_dir())
, default_dir_(filesystem::get_dir(filesystem::get_legacy_editor_dir()))
, current_addon_(addon_id)
, map_generators_()
, last_map_generator_(nullptr)
@ -84,11 +90,6 @@ context_manager::context_manager(editor_display& gui, const game_config_view& ga
, clipboard_()
{
resources::filter_con = this;
if(default_dir_.empty()) {
default_dir_ = filesystem::get_dir(filesystem::get_user_data_dir() + "/editor");
}
create_default_context();
init_map_generators(game_config);
}
@ -207,7 +208,7 @@ void context_manager::load_map_dialog(bool force_same_context /* = false */)
{
std::string fn = get_map_context().get_filename();
if(fn.empty()) {
fn = filesystem::get_legacy_editor_dir()+"/maps";
fn = filesystem::get_current_editor_dir(current_addon_) +"/maps";
}
gui2::dialogs::file_dialog dlg;
@ -243,7 +244,7 @@ void context_manager::edit_side_dialog(int side_index)
void context_manager::edit_pbl()
{
if(current_addon_ != "") {
if(!current_addon_.empty()) {
std::string pbl = filesystem::get_current_editor_dir(current_addon_) + "/_server.pbl";
gui2::dialogs::editor_edit_pbl::execute(pbl, current_addon_);
}
@ -266,7 +267,7 @@ void context_manager::change_addon_id()
current_addon_ = new_addon_id;
for(context_ptr& context : map_contexts_) {
for(std::unique_ptr<map_context>& context : map_contexts_) {
context->set_addon_id(current_addon_);
}
}
@ -673,9 +674,11 @@ void context_manager::resize_map_dialog()
void context_manager::save_map_as_dialog()
{
bool first_pick = false;
std::string input_name = get_map_context().get_filename();
if(input_name.empty()) {
input_name = filesystem::get_legacy_editor_dir()+"/maps";
first_pick = true;
input_name = filesystem::get_current_editor_dir(editor_controller::current_addon_id_)+"/maps";
}
gui2::dialogs::file_dialog dlg;
@ -683,20 +686,35 @@ void context_manager::save_map_as_dialog()
dlg.set_title(_("Save Map As"))
.set_save_mode(true)
.set_path(input_name)
.set_extension(".map");
.set_extension(".map")
.set_extension(".mask");
if(!dlg.show()) {
return;
}
std::size_t is_open = check_open_map(dlg.path());
boost::filesystem::path save_path(dlg.path());
// Show warning the first time user tries to save in a wrong folder
std::string last_folder = save_path.parent_path().filename().string();
if ((last_folder == "scenarios")
&& first_pick
&& (gui2::show_message(
_("Error"),
VGETTEXT("Do you really want to save $type1 in $type2 folder?", {{"type1", "map"}, {"type2", "scenarios"}}),
gui2::dialogs::message::yes_no_buttons) != gui2::retval::OK))
{
return;
}
std::size_t is_open = check_open_map(save_path.string());
if(is_open < map_contexts_.size() && is_open != static_cast<unsigned>(current_context_index_)) {
gui2::show_transient_message(_("This map is already open."), dlg.path());
gui2::show_transient_message(_("This map is already open."), save_path.string());
}
std::string old_filename = get_map_context().get_filename();
get_map_context().set_filename(dlg.path());
get_map_context().set_filename(save_path.string());
if(!write_map(true)) {
get_map_context().set_filename(old_filename);
@ -705,9 +723,11 @@ void context_manager::save_map_as_dialog()
void context_manager::save_scenario_as_dialog()
{
bool first_pick = false;
std::string input_name = get_map_context().get_filename();
if(input_name.empty()) {
input_name = filesystem::get_legacy_editor_dir()+"/scenarios";
first_pick = true;
input_name = filesystem::get_current_editor_dir(editor_controller::current_addon_id_) + "/scenarios";
}
gui2::dialogs::file_dialog dlg;
@ -722,15 +742,29 @@ void context_manager::save_scenario_as_dialog()
return;
}
std::size_t is_open = check_open_map(dlg.path());
boost::filesystem::path save_path(dlg.path());
// Show warning the first time user tries to save in a wrong folder
std::string last_folder = save_path.parent_path().filename().string();
if ((last_folder == "maps")
&& first_pick
&& (gui2::show_message(
_("Error"),
VGETTEXT("Do you really want to save $type1 in $type2 folder?", {{"type1", "scenario"}, {"type2", "maps"}}),
gui2::dialogs::message::yes_no_buttons) != gui2::retval::OK))
{
return;
}
std::size_t is_open = check_open_map(save_path.string());
if(is_open < map_contexts_.size() && is_open != static_cast<unsigned>(current_context_index_)) {
gui2::show_transient_message(_("This scenario is already open."), dlg.path());
gui2::show_transient_message(_("This scenario is already open."), save_path.string());
return;
}
std::string old_filename = get_map_context().get_filename();
get_map_context().set_filename(dlg.path());
get_map_context().set_filename(save_path.string());
if(!write_scenario(true)) {
get_map_context().set_filename(old_filename);
@ -804,34 +838,25 @@ void context_manager::fill_selection()
perform_refresh(editor_action_paint_area(get_map_context().map().selection(), get_selected_bg_terrain()));
}
void context_manager::save_all_maps(bool auto_save_windows)
void context_manager::save_all_maps()
{
int current = current_context_index_;
saved_windows_.clear();
for(std::size_t i = 0; i < map_contexts_.size(); ++i) {
switch_context(i);
std::string name = get_map_context().get_filename();
if(auto_save_windows) {
if(name.empty() || filesystem::is_directory(name)) {
std::ostringstream s;
s << default_dir_ << "/" << "window_" << i + 1;
if(!get_map_context().is_embedded() && !get_map_context().is_pure_map()) {
s << ".cfg";
} else {
s << ".map";
}
name = s.str();
get_map_context().set_filename(name);
}
}
saved_windows_.push_back(name);
save_map();
}
switch_context(current);
}
void context_manager::save_map()
void context_manager::save_contexts()
{
saved_contexts_.swap(map_contexts_);
std::swap(last_context_, current_context_index_);
create_blank_context();
switch_context(0, true);
}
void context_manager::save_map(bool show_confirmation)
{
const std::string& name = get_map_context().get_filename();
if(name.empty() || filesystem::is_directory(name)) {
@ -842,9 +867,9 @@ void context_manager::save_map()
}
} else {
if(get_map_context().is_pure_map()) {
write_map();
write_map(show_confirmation);
} else {
write_scenario();
write_scenario(show_confirmation);
}
}
}
@ -908,17 +933,17 @@ void context_manager::load_map(const std::string& filename, bool new_context)
}
if(filesystem::ends_with(filename, ".cfg")) {
if(editor_controller::current_addon_id_ == "") {
if(editor_controller::current_addon_id_.empty()) {
// if no addon id has been set and the file being loaded is from an addon
// then use the file path to determine the addon rather than showing a dialog
editor_controller::current_addon_id_ = filesystem::get_addon_id_from_path(filename);
if(editor_controller::current_addon_id_ == "") {
if(editor_controller::current_addon_id_.empty()) {
editor_controller::current_addon_id_ = editor::initialize_addon();
}
set_addon_id(editor_controller::current_addon_id_);
}
if(editor_controller::current_addon_id_ == "") {
if(editor_controller::current_addon_id_.empty()) {
return;
}
}
@ -926,7 +951,7 @@ void context_manager::load_map(const std::string& filename, bool new_context)
LOG_ED << "Load map: " << filename << (new_context ? " (new)" : " (same)");
try {
{
context_ptr mc(new map_context(game_config_, filename, current_addon_));
auto mc = std::make_unique<map_context>(game_config_, filename, current_addon_);
if(mc->get_filename() != filename) {
if(new_context && check_switch_open_map(mc->get_filename())) {
return;
@ -1009,11 +1034,11 @@ void context_manager::new_scenario(int width, int height, const t_translation::t
template<typename... T>
int context_manager::add_map_context(const T&... args)
{
map_contexts_.emplace_back(new map_context(args...));
map_contexts_.emplace_back(std::make_unique<map_context>(args...));
return map_contexts_.size() - 1;
}
int context_manager::add_map_context_of(context_ptr&& mc)
int context_manager::add_map_context_of(std::unique_ptr<map_context>&& mc)
{
map_contexts_.emplace_back(std::move(mc));
return map_contexts_.size() - 1;
@ -1022,11 +1047,10 @@ int context_manager::add_map_context_of(context_ptr&& mc)
template<typename... T>
void context_manager::replace_map_context(const T&... args)
{
context_ptr new_mc(new map_context(args...));
replace_map_context_with(std::move(new_mc));
replace_map_context_with(std::move(std::make_unique<map_context>(args...)));
}
void context_manager::replace_map_context_with(context_ptr&& mc)
void context_manager::replace_map_context_with(std::unique_ptr<map_context>&& mc)
{
map_contexts_[current_context_index_].swap(mc);
refresh_on_context_change();
@ -1034,19 +1058,23 @@ void context_manager::replace_map_context_with(context_ptr&& mc)
void context_manager::create_default_context()
{
if(saved_windows_.empty()) {
t_translation::terrain_code default_terrain =
if(saved_contexts_.empty()) {
create_blank_context();
switch_context(0, true);
} else {
saved_contexts_.swap(map_contexts_);
switch_context(last_context_, true);
last_context_ = 0;
}
}
void context_manager::create_blank_context()
{
t_translation::terrain_code default_terrain =
t_translation::read_terrain_code(game_config::default_terrain);
const config& default_schedule = game_config_.find_mandatory_child("editor_times", "id", "empty");
add_map_context(editor_map(44, 33, default_terrain), true, default_schedule, current_addon_);
} else {
for(const std::string& filename : saved_windows_) {
add_map_context(game_config_, filename, current_addon_);
}
saved_windows_.clear();
}
const config& default_schedule = game_config_.find_mandatory_child("editor_times", "id", "empty");
add_map_context(editor_map(44, 33, default_terrain), true, default_schedule, current_addon_);
}
void context_manager::close_current_context()

View file

@ -29,8 +29,6 @@ namespace editor
class context_manager : public filter_context
{
public:
using context_ptr = std::unique_ptr<map_context>;
context_manager(editor_display& gui, const game_config_view& game_config, const std::string& addon_id);
~context_manager();
@ -75,15 +73,15 @@ public:
*/
void perform_refresh(const editor_action& action, bool drag_part = false);
/**
* Save all maps, open dialog if not named yet, except when using
* auto_save_windows which will name unnamed maps "windows_N".
* Also record all filenames for future reopening.
*/
void save_all_maps(bool auto_save_windows = false);
/** Save all open map_contexts to memory */
void save_contexts();
/** Save all maps, show save dialogs for unsaved ones */
void save_all_maps();
/** Save the map, open dialog if not named yet. */
void save_map();
void save_map(bool show_confirmation = true);
editor_display& gui()
{
@ -229,7 +227,7 @@ private:
template<typename... T>
int add_map_context(const T&... args);
int add_map_context_of(context_ptr&& mc);
int add_map_context_of(std::unique_ptr<map_context>&& mc);
/**
* Replace the current map context and refresh accordingly
@ -237,14 +235,16 @@ private:
template<typename... T>
void replace_map_context(const T&... args);
void replace_map_context_with(context_ptr&& mc);
void replace_map_context_with(std::unique_ptr<map_context>&& mc);
/**
* Creates a default map context object, used to ensure there is always at least one.
* Except when we saved windows, in which case reopen them
* When we have saved contexts, reopen them instead.
*/
void create_default_context();
void create_blank_context();
/** Performs the necessary housekeeping necessary when switching contexts. */
void refresh_on_context_change();
@ -266,8 +266,8 @@ private:
* Save the map under a given filename. Displays an error message on failure.
* @return true on success
*/
bool write_map(bool display_confirmation = false);
bool write_scenario(bool display_confirmation = false);
bool write_map(bool display_confirmation = true);
bool write_scenario(bool display_confirmation = true);
/**
* Create a new map.
@ -335,7 +335,7 @@ private:
int auto_update_transitions_;
/** The currently opened map context object */
std::vector<context_ptr> map_contexts_;
std::vector<std::unique_ptr<map_context>> map_contexts_;
/** Clipboard map_fragment -- used for copy-paste. */
map_fragment clipboard_;

View file

@ -23,6 +23,7 @@
#include "formula/string_utils.hpp"
#include "gettext.hpp"
#include "gui/dialogs/message.hpp"
#include "gui/dialogs/transient_message.hpp"
#include "map/label.hpp"
#include "preferences/preferences.hpp"
#include "serialization/binary_or_text.hpp"
@ -723,6 +724,10 @@ config map_context::to_config()
}
// [unit]s
config traits;
preproc_map traits_map;
read(traits, *(preprocess_file(game_config::path+"/data/core/macros/traits.cfg", &traits_map)));
for(const auto& unit : units_) {
config& u = event.add_child("unit");
@ -744,6 +749,15 @@ config map_context::to_config()
if(unit.unrenamable()) {
u["unrenamable"] = unit.unrenamable();
}
if(unit.loyal()) {
config trait_loyal;
read(trait_loyal, traits_map["TRAIT_LOYAL"].value);
u.append(trait_loyal);
}
//TODO this entire block could also be replaced by unit.write(u, true)
//however, the resultant config is massive and contains many attributes we don't need.
//need to find a middle ground here.
}
// [side]s
@ -800,8 +814,7 @@ void map_context::save_schedule(const std::string& schedule_id, const std::strin
} catch(const filesystem::io_exception& e) {
utils::string_map symbols;
symbols["msg"] = e.what();
//TODO : Needs to be replaced with a better message later.
const std::string msg = VGETTEXT("Could not save the scenario: $msg", symbols);
const std::string msg = VGETTEXT("Could not save time schedule: $msg", symbols);
throw editor_map_save_exception(msg);
}
@ -820,6 +833,7 @@ void map_context::save_schedule(const std::string& schedule_id, const std::strin
std::stringstream wml_stream;
wml_stream
<< "#textdomain " << current_textdomain << "\n"
<< "#\n"
<< "# This file was generated using the scenario editor.\n"
<< "#\n"
@ -834,14 +848,13 @@ void map_context::save_schedule(const std::string& schedule_id, const std::strin
if(!wml_stream.str().empty()) {
filesystem::write_file(schedule_path, wml_stream.str());
gui2::show_transient_message("", _("Time schedule saved."));
}
} catch(const filesystem::io_exception& e) {
utils::string_map symbols;
symbols["msg"] = e.what();
//TODO : Needs to be replaced with a better message later.
const std::string msg = VGETTEXT("Could not save the scenario: $msg", symbols);
const std::string msg = VGETTEXT("Could not save time schedule: $msg", symbols);
throw editor_map_save_exception(msg);
}
}

View file

@ -447,7 +447,7 @@ protected:
void perform_action_between_stacks(action_stack& from, action_stack& to);
/**
* The undo stack. A double-ended queues due to the need to add items to one end,
* The undo stack. A double-ended queue due to the need to add items to one end,
* and remove from both when performing the undo or when trimming the size. This container owns
* all contents, i.e. no action in the stack shall be deleted, and unless otherwise noted the contents
* could be deleted at an time during normal operation of the stack. To work on an action, either

View file

@ -1467,6 +1467,41 @@ std::string normalize_path(const std::string& fpath, bool normalize_separators,
}
}
bool to_asset_path(std::string& path, std::string addon_id, std::string asset_type)
{
std::string rel_path = "";
std::string core_asset_dir = get_dir(game_config::path + "/data/core/" + asset_type);
std::string addon_asset_dir;
bool found = false;
bool is_in_core_dir = (path.find(core_asset_dir) != std::string::npos);
bool is_in_addon_dir = false;
if (is_in_core_dir) {
rel_path = path.erase(0, core_asset_dir.size()+1);
found = true;
} else if (!addon_id.empty()) {
addon_asset_dir = get_current_editor_dir(addon_id) + "/" + asset_type;
is_in_addon_dir = (path.find(addon_asset_dir) != std::string::npos);
if (is_in_addon_dir) {
rel_path = path.erase(0, addon_asset_dir.size()+1);
found = true;
} else {
// Not found in either core or addons dirs,
// return a possible path where the asset could be copied.
std::string filename = boost::filesystem::path(path).filename().string();
std::string asset_path = addon_asset_dir + "/" + filename;
rel_path = filename;
found = false;
}
} else {
found = false;
}
path = rel_path;
return found;
}
/**
* The paths manager is responsible for recording the various paths
* that binary files may be located at.

View file

@ -345,6 +345,11 @@ std::string normalize_path(const std::string& path,
bool normalize_separators = false,
bool resolve_dot_entries = false);
/** Helper function to convert absolute path to wesnoth relative path */
bool to_asset_path(std::string& abs_path,
std::string addon_id,
std::string asset_type);
/**
* Sanitizes a path to remove references to the user's name.
*/

View file

@ -24,13 +24,16 @@
#include "gettext.hpp"
#include "gui/auxiliary/field.hpp"
#include "gui/dialogs/file_dialog.hpp"
#include "gui/dialogs/message.hpp"
#include "gui/widgets/button.hpp"
#include "gui/widgets/image.hpp"
#include "gui/widgets/label.hpp"
#include "gui/widgets/slider.hpp"
#include "gui/widgets/text_box.hpp"
#include "sound.hpp"
#include <functional>
#include <boost/filesystem.hpp>
namespace gui2::dialogs
{
@ -55,8 +58,9 @@ static custom_tod::string_pair tod_getter_sound(const time_of_day& tod)
REGISTER_DIALOG(custom_tod)
custom_tod::custom_tod(const std::vector<time_of_day>& times, int current_time)
custom_tod::custom_tod(const std::vector<time_of_day>& times, int current_time, const std::string addon_id)
: modal_dialog(window_id())
, addon_id_(addon_id)
, times_(times)
, current_tod_(current_time)
, color_field_r_(register_integer("tod_red", true))
@ -82,12 +86,10 @@ void custom_tod::pre_show(window& window)
window.add_to_tab_order(find_widget<text_box>(&window, "tod_id", false, true));
for(const auto& data : metadata_stuff) {
find_widget<text_box>(&window, "path_" + data.first, false).set_active(false);
button& copy_w = find_widget<button>(&window, "copy_" + data.first, false);
connect_signal_mouse_left_click(copy_w,
std::bind(&custom_tod::copy_to_clipboard_callback, this, data.second));
std::bind(&custom_tod::copy_to_clipboard_callback, this, data));
if(!desktop::clipboard::available()) {
copy_w.set_active(false);
@ -107,6 +109,18 @@ void custom_tod::pre_show(window& window)
find_widget<button>(&window, "browse_sound", false),
std::bind(&custom_tod::select_file<tod_getter_sound>, this, "data/core/sounds/ambient"));
connect_signal_mouse_left_click(
find_widget<button>(&window, "preview_image", false),
std::bind(&custom_tod::update_image, this, "image"));
connect_signal_mouse_left_click(
find_widget<button>(&window, "preview_mask", false),
std::bind(&custom_tod::update_image, this, "mask"));
connect_signal_mouse_left_click(
find_widget<button>(&window, "preview_sound", false),
std::bind(&custom_tod::play_sound, this));
connect_signal_mouse_left_click(
find_widget<button>(&window, "next_tod", false),
std::bind(&custom_tod::do_next_tod, this));
@ -124,7 +138,7 @@ void custom_tod::pre_show(window& window)
std::bind(&custom_tod::do_delete_tod, this));
connect_signal_mouse_left_click(
find_widget<button>(&window, "preview", false),
find_widget<button>(&window, "preview_color", false),
std::bind(&custom_tod::preview_schedule, this));
connect_signal_notify_modified(
@ -166,12 +180,29 @@ void custom_tod::select_file(const std::string& default_dir)
if(dlg.show()) {
dn = dlg.path();
const std::string& message
= _("This file is outside Wesnoth's data dirs. Do you wish to copy it into your add-on?");
if(data.first == "image") {
if (!filesystem::to_asset_path(dn, addon_id_, "images")) {
if(gui2::show_message(_("Confirm"), message, message::yes_no_buttons) == gui2::retval::OK) {
filesystem::copy_file(dlg.path(), dn);
}
}
times_[current_tod_].image = dn;
} else if(data.first == "mask") {
if (!filesystem::to_asset_path(dn, addon_id_, "images")) {
if(gui2::show_message(_("Confirm"), message, message::yes_no_buttons) == gui2::retval::OK) {
filesystem::copy_file(dlg.path(), dn);
}
}
times_[current_tod_].image_mask = dn;
} else if(data.first == "sound") {
if (!filesystem::to_asset_path(dn, addon_id_, "sounds")) {
if(gui2::show_message(_("Confirm"), message, message::yes_no_buttons) == gui2::retval::OK) {
filesystem::copy_file(dlg.path(), dn);
}
}
times_[current_tod_].sounds = dn;
}
}
@ -243,6 +274,18 @@ void custom_tod::color_slider_callback(COLOR_TYPE type)
update_tod_display();
}
void custom_tod::play_sound() {
std::string sound_path = find_widget<text_box>(get_window(), "path_sound", false).get_value();
sound::play_sound(sound_path, sound::SOUND_SOURCES);
}
void custom_tod::update_image(const std::string& id_stem) {
std::string img_path = find_widget<text_box>(get_window(), "path_"+id_stem, false).get_value();
find_widget<image>(get_window(), "current_tod_" + id_stem, false).set_label(img_path);
get_window()->invalidate_layout();
}
void custom_tod::update_tod_display()
{
display* disp = display::get_singleton();
@ -251,8 +294,7 @@ void custom_tod::update_tod_display()
// The display handles invaliding whatever tiles need invalidating.
disp->update_tod(&get_selected_tod());
// NOTE: revert to invalidate_layout if necessary to display the ToD mask image.
get_window()->queue_redraw();
get_window()->invalidate_layout();
}
void custom_tod::update_lawful_bonus()
@ -287,9 +329,12 @@ void custom_tod::update_selected_tod_info()
update_tod_display();
}
void custom_tod::copy_to_clipboard_callback(tod_attribute_getter getter)
void custom_tod::copy_to_clipboard_callback(std::pair<std::string, tod_attribute_getter> data)
{
auto& [type, getter] = data;
button& copy_w = find_widget<button>(get_window(), "copy_" + type, false);
desktop::clipboard::copy_to_clipboard(getter(get_selected_tod()).second, false);
copy_w.set_success(true);
}
/** Quickly preview the schedule changes and color */

View file

@ -30,7 +30,7 @@ namespace dialogs
class custom_tod : public modal_dialog
{
public:
custom_tod(const std::vector<time_of_day>& times, int current_time);
custom_tod(const std::vector<time_of_day>& times, int current_time, const std::string addon_id = "");
/** The execute function. See @ref modal_dialog for more information. */
DEFINE_SIMPLE_EXECUTE_WRAPPER(custom_tod)
@ -82,15 +82,24 @@ private:
void update_selected_tod_info();
void copy_to_clipboard_callback(tod_attribute_getter getter);
void copy_to_clipboard_callback(std::pair<std::string, tod_attribute_getter> data);
/** Update current TOD with values from the GUI */
void update_schedule();
/** Available time_of_days */
/** Update image when preview is pressed */
void update_image(const std::string& id_stem);
/** Play sound when play is pressed */
void play_sound();
/** ID of the current addon. The schedule file will be saved here. */
const std::string addon_id_;
/** Available time of days */
std::vector<time_of_day> times_;
/** Current ToD index */
/** Current time of day (ToD) index */
int current_tod_;
field_integer* color_field_r_;

View file

@ -22,29 +22,32 @@
#include "filesystem.hpp"
#include "formula/string_utils.hpp"
#include "gettext.hpp"
#include "units/types.hpp"
#include "gui/dialogs/unit_create.hpp"
#include "gui/auxiliary/find_widget.hpp"
#include "gui/dialogs/file_dialog.hpp"
#include "gui/dialogs/message.hpp"
#include "gui/dialogs/unit_create.hpp"
#include "gui/dialogs/transient_message.hpp"
#include "gui/widgets/button.hpp"
#include "gui/widgets/image.hpp"
#include "gui/widgets/scroll_label.hpp"
#include "gui/widgets/spinner.hpp"
#include "gui/widgets/label.hpp"
#include "gui/widgets/listbox.hpp"
#include "gui/widgets/menu_button.hpp"
#include "gui/widgets/scroll_text.hpp"
#include "gui/widgets/multimenu_button.hpp"
#include "gui/widgets/scroll_label.hpp"
#include "gui/widgets/scroll_text.hpp"
#include "gui/widgets/slider.hpp"
#include "gui/widgets/stacked_widget.hpp"
#include "gui/widgets/spinner.hpp"
#include "gui/widgets/tab_container.hpp"
#include "gui/widgets/text_box.hpp"
#include "gui/widgets/toggle_button.hpp"
#include "gui/auxiliary/find_widget.hpp"
#include "picture.hpp"
#include "serialization/binary_or_text.hpp"
#include "serialization/parser.hpp"
#include "serialization/preprocessor.hpp"
#include "units/types.hpp"
#include <boost/filesystem.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem.hpp>
#include <sstream>
namespace gui2::dialogs
@ -66,7 +69,7 @@ editor_edit_unit::editor_edit_unit(const game_config_view& game_config, const st
read(specials, *(preprocess_file(game_config::path+"/data/core/macros/abilities.cfg", &abilities_map_)));
for (const auto& x : abilities_map_) {
/** Don't add any macros that have INTERNAL */
// Don't add any macros that have INTERNAL
if (x.first.find("INTERNAL") == std::string::npos) {
abilities_list_.emplace_back("label", x.first, "checkbox", false);
}
@ -77,6 +80,15 @@ editor_edit_unit::editor_edit_unit(const game_config_view& game_config, const st
}
void editor_edit_unit::pre_show(window& win) {
tab_container& tabs = find_widget<tab_container>(&win, "tabs", false);
connect_signal_notify_modified(tabs, std::bind(&editor_edit_unit::on_page_select, this));
//
// Main Stats tab
//
tabs.select_tab(0);
menu_button& alignments = find_widget<menu_button>(&win, "alignment_list", false);
// TODO:change alignments to existing translatable strings
align_list_.emplace_back("label", _("lawful"));
@ -95,6 +107,42 @@ void editor_edit_unit::pre_show(window& win) {
races.set_values(race_list_);
}
button& load = find_widget<button>(&win, "load_unit_type", false);
std::stringstream tooltip;
tooltip << vgettext_impl("wesnoth", "Hotkey(s): ", {{}});
#ifdef __APPLE__
tooltip << "cmd+o";
#else
tooltip << "ctrl+o";
#endif
load.set_tooltip(tooltip.str());
connect_signal_mouse_left_click(load, std::bind(&editor_edit_unit::load_unit_type, this));
connect_signal_mouse_left_click(
find_widget<button>(&win, "browse_unit_image", false),
std::bind(&editor_edit_unit::select_file, this, "data/core/images/units", "unit_image"));
connect_signal_mouse_left_click(
find_widget<button>(&win, "preview_unit_image", false),
std::bind(&editor_edit_unit::update_image, this, "unit_image"));
connect_signal_mouse_left_click(
find_widget<button>(&win, "browse_portrait_image", false),
std::bind(&editor_edit_unit::select_file, this, "data/core/images/portraits", "portrait_image"));
connect_signal_mouse_left_click(
find_widget<button>(&win, "preview_portrait_image", false),
std::bind(&editor_edit_unit::update_image, this, "portrait_image"));
connect_signal_notify_modified(
find_widget<text_box>(&win, "name_box", false),
std::bind(&editor_edit_unit::button_state_change, this));
connect_signal_notify_modified(
find_widget<text_box>(&win, "id_box", false),
std::bind(&editor_edit_unit::button_state_change, this));
//
// Advanced Tab
//
tabs.select_tab(1);
menu_button& movetypes = find_widget<menu_button>(&win, "movetype_list", false);
for(const auto& mt : unit_types.movement_types()) {
movetype_list_.emplace_back("label", mt.first);
@ -125,7 +173,6 @@ void editor_edit_unit::pre_show(window& win) {
}
menu_button& resistances = find_widget<menu_button>(&win, "resistances_list", false);
menu_button& attack_types = find_widget<menu_button>(&win, "attack_type_list", false);
const config& resistances_attr = game_config_
.mandatory_child("units")
@ -137,7 +184,6 @@ void editor_edit_unit::pre_show(window& win) {
if (resistances_list_.size() > 0) {
resistances.set_values(resistances_list_);
attack_types.set_values(resistances_list_);
res_toggles_.resize(resistances_list_.size());
}
@ -149,57 +195,18 @@ void editor_edit_unit::pre_show(window& win) {
usage_type_list_.emplace_back("label", _("healer"));
usage_types.set_values(usage_type_list_);
multimenu_button& specials = find_widget<multimenu_button>(&win, "weapon_specials_list", false);
specials.set_values(specials_list_);
multimenu_button& abilities = find_widget<multimenu_button>(&win, "abilities_list", false);
abilities.set_values(abilities_list_);
group<std::string> range_group;
range_group.add_member(find_widget<toggle_button>(&win, "range_melee", false, true), "melee");
range_group.add_member(find_widget<toggle_button>(&win, "range_ranged", false, true), "ranged");
range_group.set_member_states("melee");
// Connect signals
connect_signal_mouse_left_click(
find_widget<button>(&win, "browse_unit_image", false),
std::bind(&editor_edit_unit::select_file, this, "data/core/images/units", "unit_image"));
connect_signal_mouse_left_click(
find_widget<button>(&win, "preview_unit_image", false),
std::bind(&editor_edit_unit::update_image, this, "unit_image"));
connect_signal_mouse_left_click(
find_widget<button>(&win, "browse_portrait_image", false),
std::bind(&editor_edit_unit::select_file, this, "data/core/images/portraits", "portrait_image"));
connect_signal_mouse_left_click(
find_widget<button>(&win, "preview_portrait_image", false),
std::bind(&editor_edit_unit::update_image, this, "portrait_image"));
connect_signal_mouse_left_click(
find_widget<button>(&win, "browse_small_profile_image", false),
std::bind(&editor_edit_unit::select_file, this, "data/core/images/portraits", "small_profile_image"));
connect_signal_mouse_left_click(
find_widget<button>(&win, "preview_small_profile_image", false),
std::bind(&editor_edit_unit::update_image, this, "small_profile_image"));
connect_signal_mouse_left_click(
find_widget<button>(&win, "browse_attack_image", false),
std::bind(&editor_edit_unit::select_file, this, "data/core/images/attacks", "attack_image"));
connect_signal_mouse_left_click(
find_widget<button>(&win, "preview_attack_image", false),
std::bind(&editor_edit_unit::update_image, this, "attack_image"));
button& load = find_widget<button>(&win, "load_unit_type", false);
connect_signal_mouse_left_click(load, std::bind(&editor_edit_unit::load_unit_type, this));
std::stringstream tooltip;
tooltip << vgettext_impl("wesnoth", "Hotkey(s): ", {{}});
#ifdef __APPLE__
tooltip << "cmd+o";
#else
tooltip << "ctrl+o";
#endif
load.set_tooltip(tooltip.str());
connect_signal_mouse_left_click(
find_widget<button>(&win, "load_movetype", false),
std::bind(&editor_edit_unit::load_movetype, this));
connect_signal_notify_modified(
find_widget<slider>(&win, "resistances_slider", false),
std::bind(&editor_edit_unit::store_resistances, this));
@ -235,28 +242,39 @@ void editor_edit_unit::pre_show(window& win) {
}
if (!def_toggles_.empty()) {
enable_defense_slider();
enable_defense_slider();
}
if (!move_toggles_.empty()) {
enable_movement_slider();
enable_movement_slider();
}
//
// Attack Tab
//
tabs.select_tab(2);
multimenu_button& specials = find_widget<multimenu_button>(&win, "weapon_specials_list", false);
specials.set_values(specials_list_);
group<std::string> range_group;
range_group.add_member(find_widget<toggle_button>(&win, "range_melee", false, true), "melee");
range_group.add_member(find_widget<toggle_button>(&win, "range_ranged", false, true), "ranged");
range_group.set_member_states("melee");
menu_button& attack_types = find_widget<menu_button>(&win, "attack_type_list", false);
if (resistances_list_.size() > 0) {
attack_types.set_values(resistances_list_);
}
// Connect signals
connect_signal_mouse_left_click(
find_widget<button>(&win, "browse_attack_image", false),
std::bind(&editor_edit_unit::select_file, this, "data/core/images/attacks", "attack_image"));
connect_signal_mouse_left_click(
find_widget<button>(&win, "preview_attack_image", false),
std::bind(&editor_edit_unit::update_image, this, "attack_image"));
connect_signal_notify_modified(
find_widget<menu_button>(&win, "atk_list", false),
std::bind(&editor_edit_unit::select_attack, this));
connect_signal_notify_modified(
find_widget<text_box>(&win, "name_box", false),
std::bind(&editor_edit_unit::button_state_change, this));
connect_signal_notify_modified(
find_widget<text_box>(&win, "id_box", false),
std::bind(&editor_edit_unit::button_state_change, this));
// Disable OK button at start, since ID and Name boxes are empty
button_state_change();
// Attack page
connect_signal_mouse_left_click(
find_widget<button>(&win, "atk_new", false),
std::bind(&editor_edit_unit::add_attack, this));
@ -272,31 +290,20 @@ void editor_edit_unit::pre_show(window& win) {
update_index();
// Setup tabs
listbox& selector = find_widget<listbox>(&win, "tabs", false);
connect_signal_notify_modified(selector,
std::bind(&editor_edit_unit::on_page_select, this));
stacked_widget& page = find_widget<stacked_widget>(&win, "page", false);
win.keyboard_capture(&selector);
tabs.select_tab(0);
int main_index = 0;
selector.select_row(main_index);
page.select_layer(main_index);
// Disable OK button at start, since ID and Name boxes are empty
button_state_change();
}
void editor_edit_unit::on_page_select()
{
save_unit_type();
const int selected_row =
std::max(0, find_widget<listbox>(get_window(), "tabs", false).get_selected_row());
find_widget<stacked_widget>(get_window(), "page", false).select_layer(static_cast<unsigned int>(selected_row));
if (selected_row == 3) {
tab_container& tabs = find_widget<tab_container>(get_window(), "tabs", false);
if (tabs.get_active_tab_index() == 3) {
update_wml_view();
}
get_window()->invalidate_layout();
}
void editor_edit_unit::select_file(const std::string& default_dir, const std::string& id_stem)
@ -309,46 +316,37 @@ void editor_edit_unit::select_file(const std::string& default_dir, const std::st
if (dlg.show()) {
/* Convert absolute path to wesnoth relative path */
std::string images_dir = filesystem::get_core_images_dir();
std::string addons_dir = filesystem::get_current_editor_dir(addon_id_) + "/images";
std::stringstream path;
std::string dn = dlg.path();
const std::string& message
= _("This file is outside Wesnoth's data dirs. Do you wish to copy it into your add-on?");
if ((dlg.path().find(images_dir) == std::string::npos)
&& (dlg.path().find(addons_dir) == std::string::npos)) {
/* choosen file is outside wesnoth's images dir,
* copy image to addons directory */
std::string filename = boost::filesystem::path(dlg.path()).filename().string();
if(id_stem == "unit_image") {
if (id_stem == "unit_image") {
path << addons_dir + "/units/" + filename;
} else if ((id_stem == "portrait_image")||(id_stem == "small_profile_image")) {
path << addons_dir + "/portraits/" + filename;
} else if (id_stem == "attack_image") {
path << addons_dir + "/attacks/" + filename;
if (!filesystem::to_asset_path(dn, addon_id_, "images")) {
if(gui2::show_message(_("Confirm"), message, message::yes_no_buttons) == gui2::retval::OK) {
filesystem::copy_file(dlg.path(), dn);
}
}
} else if((id_stem == "portrait_image")||(id_stem == "small_profile_image")) {
if (!filesystem::to_asset_path(dn, addon_id_, "images")) {
if(gui2::show_message(_("Confirm"), message, message::yes_no_buttons) == gui2::retval::OK) {
filesystem::copy_file(dlg.path(), dn);
}
}
} else if(id_stem == "attack_image") {
if (!filesystem::to_asset_path(dn, addon_id_, "images")) {
if(gui2::show_message(_("Confirm"), message, message::yes_no_buttons) == gui2::retval::OK) {
filesystem::copy_file(dlg.path(), dn);
}
}
filesystem::copy_file(dlg.path(), path.str());
} else {
path << dlg.path();
}
if (path.str().find(images_dir) != std::string::npos) {
// Image in Wesnoth core dir
path.str(path.str().replace(0, images_dir.size()+1, ""));
} else if (path.str().find(addons_dir) != std::string::npos) {
// Image in addons dir
path.str(path.str().replace(0, addons_dir.size()+1, ""));
}
path.seekp(0, std::ios_base::end);
unsigned size = 200; // TODO: Arbitrary, can be changed later.
if (check_big(dlg.path(), size)) {
path << "~SCALE(" << size << "," << size << ")";
}
find_widget<text_box>(get_window(), "path_"+id_stem, false).set_value(path.str());
find_widget<text_box>(get_window(), "path_"+id_stem, false).set_value(dn);
update_image(id_stem);
}
}
@ -358,8 +356,9 @@ void editor_edit_unit::load_unit_type() {
if (dlg_uc.show()) {
const unit_type *type = unit_types.find(dlg_uc.choice());
stacked_widget& page = find_widget<stacked_widget>(get_window(), "page", false);
page.select_layer(0);
tab_container& tabs = find_widget<tab_container>(get_window(), "tabs", false);
tabs.select_tab(0);
find_widget<text_box>(get_window(), "id_box", false).set_value(type->id());
find_widget<text_box>(get_window(), "name_box", false).set_value(type->type_name().base_str());
find_widget<spinner>(get_window(), "level_box", false).set_value(type->level());
@ -396,7 +395,7 @@ void editor_edit_unit::load_unit_type() {
update_image("unit_image");
page.select_layer(1);
tabs.select_tab(1);
find_widget<text_box>(get_window(), "path_small_profile_image", false).set_value(type->small_profile());
set_selected_from_string(
@ -452,7 +451,7 @@ void editor_edit_unit::load_unit_type() {
update_image("small_profile_image");
page.select_layer(2);
tabs.select_tab(2);
attacks_.clear();
for(const auto& atk : type->attacks())
{
@ -472,9 +471,10 @@ void editor_edit_unit::load_unit_type() {
update_attacks();
update_index();
page.select_layer(0);
tabs.select_tab(0);
button_state_change();
get_window()->invalidate_layout();
}
}
@ -486,45 +486,46 @@ void editor_edit_unit::save_unit_type() {
// Textdomain
std::string current_textdomain = "wesnoth-"+addon_id_;
stacked_widget& page = find_widget<stacked_widget>(get_window(), "page", false);
tab_container& tabs = find_widget<tab_container>(get_window(), "tabs", false);
// Page 1
page.select_layer(0);
grid* grid = tabs.get_tab_grid(0);
config& utype = type_cfg_.add_child("unit_type");
utype["id"] = find_widget<text_box>(get_window(), "id_box", false).get_value();
utype["name"] = t_string(find_widget<text_box>(get_window(), "name_box", false).get_value(), current_textdomain);
utype["image"] = find_widget<text_box>(get_window(), "path_unit_image", false).get_value();
utype["profile"] = find_widget<text_box>(get_window(), "path_portrait_image", false).get_value();
utype["level"] = find_widget<spinner>(get_window(), "level_box", false).get_value();
utype["advances_to"] = find_widget<text_box>(get_window(), "adv_box", false).get_value();
utype["hitpoints"] = find_widget<slider>(get_window(), "hp_slider", false).get_value();
utype["experience"] = find_widget<slider>(get_window(), "xp_slider", false).get_value();
utype["cost"] = find_widget<slider>(get_window(), "cost_slider", false).get_value();
utype["movement"] = find_widget<slider>(get_window(), "move_slider", false).get_value();
utype["description"] = t_string(find_widget<scroll_text>(get_window(), "desc_box", false).get_value(), current_textdomain);
utype["race"] = find_widget<menu_button>(get_window(), "race_list", false).get_value_string();
utype["alignment"] = find_widget<menu_button>(get_window(), "alignment_list", false).get_value_string();
utype["id"] = find_widget<text_box>(grid, "id_box", false).get_value();
utype["name"] = t_string(find_widget<text_box>(grid, "name_box", false).get_value(), current_textdomain);
utype["image"] = find_widget<text_box>(grid, "path_unit_image", false).get_value();
utype["profile"] = find_widget<text_box>(grid, "path_portrait_image", false).get_value();
utype["level"] = find_widget<spinner>(grid, "level_box", false).get_value();
utype["advances_to"] = find_widget<text_box>(grid, "adv_box", false).get_value();
utype["hitpoints"] = find_widget<slider>(grid, "hp_slider", false).get_value();
utype["experience"] = find_widget<slider>(grid, "xp_slider", false).get_value();
utype["cost"] = find_widget<slider>(grid, "cost_slider", false).get_value();
utype["movement"] = find_widget<slider>(grid, "move_slider", false).get_value();
utype["description"] = t_string(find_widget<scroll_text>(grid, "desc_box", false).get_value(), current_textdomain);
utype["race"] = find_widget<menu_button>(grid, "race_list", false).get_value_string();
utype["alignment"] = find_widget<menu_button>(grid, "alignment_list", false).get_value_string();
// Gender
if (find_widget<toggle_button>(get_window(), "gender_male", false).get_value()) {
if (find_widget<toggle_button>(get_window(), "gender_female", false).get_value()) {
if (find_widget<toggle_button>(grid, "gender_male", false).get_value()) {
if (find_widget<toggle_button>(grid, "gender_female", false).get_value()) {
utype["gender"] = "male,female";
} else {
utype["gender"] = "male";
}
} else {
if (find_widget<toggle_button>(get_window(), "gender_female", false).get_value()) {
if (find_widget<toggle_button>(grid, "gender_female", false).get_value()) {
utype["gender"] = "female";
}
}
// Page 2
page.select_layer(1);
grid = tabs.get_tab_grid(1);
utype["small_profile"] = find_widget<text_box>(get_window(), "path_small_profile_image", false).get_value();
utype["movement_type"] = find_widget<menu_button>(get_window(), "movetype_list", false).get_value_string();
utype["usage"] = find_widget<menu_button>(get_window(), "usage_list", false).get_value_string();
utype["small_profile"] = find_widget<text_box>(grid, "path_small_profile_image", false).get_value();
utype["movement_type"] = find_widget<menu_button>(grid, "movetype_list", false).get_value_string();
utype["usage"] = find_widget<menu_button>(grid, "usage_list", false).get_value_string();
if (res_toggles_.any()) {
config& resistances = utype.add_child("resistance");
@ -559,7 +560,7 @@ void editor_edit_unit::save_unit_type() {
}
}
const auto& abilities_states = find_widget<multimenu_button>(get_window(), "abilities_list", false).get_toggle_states();
const auto& abilities_states = find_widget<multimenu_button>(grid, "abilities_list", false).get_toggle_states();
if (abilities_states.any()) {
unsigned int i = 0;
sel_abilities_.clear();
@ -658,8 +659,10 @@ void editor_edit_unit::store_attack() {
}
config& attack = attacks_.at(selected_attack_-1).second;
stacked_widget& page = find_widget<stacked_widget>(get_window(), "page", false);
page.select_layer(2);
tab_container& tabs = find_widget<tab_container>(get_window(), "tabs", false);
int prev_tab = tabs.get_active_tab_index();
tabs.select_tab(2);
attack["name"] = find_widget<text_box>(get_window(), "atk_id_box", false).get_value();
attack["description"] = t_string(find_widget<text_box>(get_window(), "atk_name_box", false).get_value(), current_textdomain);
@ -675,14 +678,17 @@ void editor_edit_unit::store_attack() {
}
attacks_.at(selected_attack_-1).first = find_widget<multimenu_button>(get_window(), "weapon_specials_list", false).get_toggle_states();
tabs.select_tab(prev_tab);
}
void editor_edit_unit::update_attacks() {
//Load data
config& attack = attacks_.at(selected_attack_-1).second;
stacked_widget& page = find_widget<stacked_widget>(get_window(), "page", false);
page.select_layer(2);
tab_container& tabs = find_widget<tab_container>(get_window(), "tabs", false);
int prev_tab = tabs.get_active_tab_index();
tabs.select_tab(2);
find_widget<text_box>(get_window(), "atk_id_box", false).set_value(attack["name"]);
find_widget<text_box>(get_window(), "atk_name_box", false).set_value(attack["description"]);
@ -707,9 +713,15 @@ void editor_edit_unit::update_attacks() {
find_widget<multimenu_button>(get_window(), "weapon_specials_list", false)
.select_options(attacks_.at(selected_attack_-1).first);
tabs.select_tab(prev_tab);
}
void editor_edit_unit::update_index() {
tab_container& tabs = find_widget<tab_container>(get_window(), "tabs", false);
int prev_tab = tabs.get_active_tab_index();
tabs.select_tab(2);
if (selected_attack_ <= 1) {
find_widget<button>(get_window(), "atk_prev", false).set_active(false);
} else {
@ -741,16 +753,20 @@ void editor_edit_unit::update_index() {
//Set index
const std::string new_index_str = formatter() << selected_attack_ << "/" << attacks_.size();
find_widget<label>(get_window(), "atk_number", false).set_label(new_index_str);
tabs.select_tab(prev_tab);
}
void editor_edit_unit::add_attack() {
// Textdomain
std::string current_textdomain = "wesnoth-"+addon_id_;
tab_container& tabs = find_widget<tab_container>(get_window(), "tabs", false);
int prev_tab = tabs.get_active_tab_index();
tabs.select_tab(2);
config attack;
stacked_widget& page = find_widget<stacked_widget>(get_window(), "page", false);
page.select_layer(2);
attack["name"] = find_widget<text_box>(get_window(), "atk_id_box", false).get_value();
attack["description"] = t_string(find_widget<text_box>(get_window(), "atk_name_box", false).get_value(), current_textdomain);
attack["icon"] = find_widget<text_box>(get_window(), "path_attack_image", false).get_value();
@ -772,9 +788,15 @@ void editor_edit_unit::add_attack() {
, attack));
update_index();
tabs.select_tab(prev_tab);
}
void editor_edit_unit::delete_attack() {
tab_container& tabs = find_widget<tab_container>(get_window(), "tabs", false);
int prev_tab = tabs.get_active_tab_index();
tabs.select_tab(2);
//remove attack
if (attacks_.size() > 0) {
attacks_.erase(attacks_.begin() + selected_attack_ - 1);
@ -796,6 +818,8 @@ void editor_edit_unit::delete_attack() {
}
update_index();
tabs.select_tab(prev_tab);
}
void editor_edit_unit::next_attack() {
@ -829,7 +853,12 @@ void editor_edit_unit::select_attack() {
update_index();
}
//TODO Check if works with non-mainline movetypes
void editor_edit_unit::load_movetype() {
tab_container& tabs = find_widget<tab_container>(get_window(), "tabs", false);
int prev_tab = tabs.get_active_tab_index();
tabs.select_tab(1);
for(const auto& movetype : game_config_
.mandatory_child("units")
.child_range("movetype")) {
@ -845,6 +874,8 @@ void editor_edit_unit::load_movetype() {
update_movement_costs();
}
}
tabs.select_tab(prev_tab);
}
void editor_edit_unit::write_macro(std::ostream& out, unsigned level, const std::string macro_name)
@ -860,8 +891,8 @@ void editor_edit_unit::update_wml_view() {
store_attack();
save_unit_type();
stacked_widget& page = find_widget<stacked_widget>(get_window(), "page", false);
page.select_layer(3);
tab_container& tabs = find_widget<tab_container>(get_window(), "tabs", false);
tabs.select_tab(3);
std::stringstream wml_stream;
@ -987,20 +1018,22 @@ void editor_edit_unit::update_image(const std::string& id_stem) {
rel_path = rel_path.substr(0, rel_path.find("~"));
}
std::string abs_path = filesystem::get_binary_file_location("images", rel_path);
std::stringstream mod_path(rel_path);
mod_path.seekp(0, std::ios_base::end);
unsigned size = 200; // TODO: Arbitrary, can be changed later.
if ((abs_path.size() > 0) && check_big(abs_path, size)) {
mod_path << "~SCALE(" << size << "," << size << ")";
int scale_size = 200; // TODO: Arbitrary, can be changed later.
if (rel_path.size() > 0) {
point img_size = ::image::get_size(::image::locator{rel_path});
float aspect_ratio = static_cast<float>(img_size.x)/img_size.y;
if(img_size.x > scale_size) {
rel_path.append("~SCALE(" + std::to_string(scale_size) + "," + std::to_string(scale_size*aspect_ratio) + ")");
} else if (img_size.y > scale_size) {
rel_path.append("~SCALE(" + std::to_string(scale_size/aspect_ratio) + "," + std::to_string(scale_size) + ")");
}
}
if (id_stem == "portrait_image") {
// portrait image uses same [image] as unit_image
find_widget<image>(get_window(), "unit_image", false).set_label(mod_path.str());
find_widget<image>(get_window(), "unit_image", false).set_label(rel_path);
} else {
find_widget<image>(get_window(), id_stem, false).set_label(mod_path.str());
find_widget<image>(get_window(), id_stem, false).set_label(rel_path);
}
get_window()->invalidate_layout();
@ -1010,7 +1043,7 @@ void editor_edit_unit::update_image(const std::string& id_stem) {
bool editor_edit_unit::check_id(std::string id) {
for(char c : id) {
if (!(std::isalnum(c) || c == '_' || c == ' ')) {
/* One bad char means entire id string is invalid */
// One bad char means entire id string is invalid
return false;
}
}
@ -1018,8 +1051,11 @@ bool editor_edit_unit::check_id(std::string id) {
}
void editor_edit_unit::button_state_change() {
std::string id = find_widget<text_box>(get_window(), "id_box", false).get_value();
std::string name = find_widget<text_box>(get_window(), "name_box", false).get_value();
tab_container& tabs = find_widget<tab_container>(get_window(), "tabs", false);
std::string id = find_widget<text_box>(tabs.get_tab_grid(0), "id_box", false).get_value();
std::string name = find_widget<text_box>(tabs.get_tab_grid(0), "name_box", false).get_value();
if (
id.empty()
|| name.empty()
@ -1033,13 +1069,6 @@ void editor_edit_unit::button_state_change() {
get_window()->queue_redraw();
}
void editor_edit_unit::button_state_change_id() {
std::string id = find_widget<text_box>(get_window(), "id_box", false).get_value();
find_widget<button>(get_window(), "ok", false).set_active( !id.empty() || check_id(id) );
get_window()->queue_redraw();
}
void editor_edit_unit::write() {
// Write the file
update_wml_view();
@ -1053,8 +1082,9 @@ void editor_edit_unit::write() {
// Write to file
try {
filesystem::write_file(unit_path, generated_wml);
} catch(const filesystem::io_exception& /*e*/) {
// TODO : Needs an error message
gui2::show_transient_message("", _("Unit type saved."));
} catch(const filesystem::io_exception& e) {
gui2::show_transient_message("", e.what());
}
}

View file

@ -22,8 +22,6 @@
#include "serialization/preprocessor.hpp"
#include <boost/dynamic_bitset.hpp>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
namespace gui2
{
@ -52,7 +50,10 @@ private:
config type_cfg_;
config resistances_, defenses_, movement_;
preproc_map specials_map_, abilities_map_;
/** Used to control checkboxes, so that only specific values are overridden */
/**
* Used to control checkboxes for various resistances, defences, etc.
* so that only specific values are overridden.
*/
boost::dynamic_bitset<> res_toggles_, def_toggles_, move_toggles_;
std::vector<config> align_list_, race_list_, movetype_list_, defense_list_, resistances_list_, usage_type_list_;
@ -79,14 +80,6 @@ private:
/** Save Unit Type data to cfg */
void save_unit_type();
/** Check if width/height bigger
* than a specified size */
bool check_big(std::string img_abs_path, const int scale_size)
{
SDL_Surface * img_surf = IMG_Load(img_abs_path.c_str());
return (img_surf->w > scale_size) || (img_surf->h > scale_size);
}
/** Write macro to a stream at specified tab level */
void write_macro(std::ostream& out, unsigned level, const std::string macro_name);
@ -132,7 +125,6 @@ private:
/** Callback to enable/disable OK button if ID/Name is invalid */
void button_state_change();
void button_state_change_id();
/** Utility method to check if ID contains any invalid characters */
bool check_id(std::string id);

View file

@ -1,5 +1,6 @@
/*
Copyright (C) 2023 - 2024
by Subhraman Sarkar (babaissarkar) <suvrax@gmail.com>
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
@ -27,7 +28,7 @@ namespace gui2::dialogs
REGISTER_DIALOG(tod_new_schedule);
tod_new_schedule::tod_new_schedule(std::string& schedule_id, std::string& schedule_name)
tod_new_schedule::tod_new_schedule(std::string& schedule_id, t_string& schedule_name)
: modal_dialog(window_id())
, schedule_id_(schedule_id)
, schedule_name_(schedule_name)

View file

@ -1,5 +1,6 @@
/*
Copyright (C) 2023 - 2024
by Subhraman Sarkar (babaissarkar) <suvrax@gmail.com>
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
@ -30,7 +31,7 @@ namespace dialogs
class tod_new_schedule : public modal_dialog
{
public:
tod_new_schedule(std::string& schedule_id, std::string& schedule_name);
tod_new_schedule(std::string& schedule_id, t_string& schedule_name);
/** The execute function. See @ref modal_dialog for more information. */
DEFINE_SIMPLE_EXECUTE_WRAPPER(tod_new_schedule);
@ -42,7 +43,7 @@ private:
virtual const std::string& window_id() const override;
std::string& schedule_id_;
std::string& schedule_name_;
t_string& schedule_name_;
/* Callback for enabling or disabling OK button */
void button_state_change();

View file

@ -19,6 +19,7 @@
#include "cursor.hpp"
#include "desktop/paths.hpp"
#include "desktop/open.hpp"
#include "filesystem.hpp"
#include "formula/string_utils.hpp"
#include "gui/auxiliary/find_widget.hpp"
@ -46,11 +47,9 @@ namespace fs = filesystem;
namespace
{
const std::string icon_dir = "misc/folder-icon.png";
// Empty icons with the same size as the above to force the icon column to have a
// specific size even when there are no folders in the list.
const std::string icon_file = icon_dir + "~O(0)";
const std::string icon_parent = icon_dir + "~O(0)";
const std::string icon_dir = "icons/action/browse_25.png";
const std::string icon_parent = "icons/action/undo_25.png";
const std::string icon_file = "misc/file.png";
// NOTE: Does not need to be the same as PARENT_DIR! Use PARENT_DIR to build
// relative paths for non-presentational purposes instead.
const std::string label_parent = "..";
@ -159,10 +158,54 @@ file_dialog& file_dialog::set_path(const std::string& value)
file_dialog& file_dialog::set_filename(const std::string& value)
{
current_entry_ = value;
return *this;
}
void file_dialog::check_filename() {
if(!save_mode_) {
return;
}
text_box& file_textbox = find_widget<text_box>(get_window(), "filename", false);
button& save_btn = find_widget<button>(get_window(), "ok", false);
// empty filename
std::string filename = file_textbox.get_value();
styled_widget& validation_msg = find_widget<styled_widget>(get_window(), "validation_msg", false);
bool stat_invalid = filename.empty() || (filename.substr(0,1) == ".");
bool wrong_ext = false;
if (stat_invalid) {
validation_msg.set_label("<span color='#00dcff' size='small'>please enter a filename</span>");
save_btn.set_active(false);
} else {
// wrong extension check
for (const auto& extension : extensions_) {
if (filename.size() >= extension.size()) {
std::string ext = filename.substr(filename.size()-extension.size());
if (ext == extension) {
wrong_ext = false;
break;
} else {
wrong_ext = true;
}
} else {
// size of allowed extensions and the one typed don't match
wrong_ext = true;
}
}
if (wrong_ext) {
validation_msg.set_label("<span color='red' face='DejaVuSans'>✘</span><span color='red' size='small'>wrong extension, use " + utils::join(extensions_, ", ") + "</span>");
save_btn.set_active(false);
} else {
validation_msg.set_label("");
save_btn.set_active(true);
}
}
}
void file_dialog::pre_show(window& window)
{
styled_widget& title = find_widget<styled_widget>(&window, "title", false);
@ -228,16 +271,22 @@ void file_dialog::pre_show(window& window)
sync_bookmarks_bar();
listbox& filelist = find_widget<listbox>(&window, "filelist", false);
text_box& file_textbox = find_widget<text_box>(get_window(), "filename", false);
connect_signal_notify_modified(filelist,
std::bind(&file_dialog::on_row_selected, this));
connect_signal_notify_modified(bookmarks_bar,
std::bind(&file_dialog::on_bookmark_selected, this));
connect_signal_notify_modified(file_textbox,
std::bind(&file_dialog::check_filename, this));
check_filename();
button& mkdir_button = find_widget<button>(&window, "new_dir", false);
button& rm_button = find_widget<button>(&window, "delete_file", false);
button& bookmark_add_button = find_widget<button>(&window, "add_bookmark", false);
button& bookmark_del_button = find_widget<button>(&window, "remove_bookmark", false);
button& open_ext_button = find_widget<button>(&window, "open_ext", false);
connect_signal_mouse_left_click(mkdir_button,
std::bind(&file_dialog::on_dir_create_cmd, this));
@ -248,6 +297,14 @@ void file_dialog::pre_show(window& window)
connect_signal_mouse_left_click(bookmark_del_button,
std::bind(&file_dialog::on_bookmark_del_cmd, this));
if (desktop::open_object_is_supported()) {
connect_signal_mouse_left_click(open_ext_button,
std::bind([this](){ desktop::open_object(path()); }));
} else {
open_ext_button.set_active(false);
open_ext_button.set_tooltip(_("Opening files is not supported, contact your packager"));
}
if(read_only_) {
mkdir_button.set_active(false);
rm_button.set_active(false);
@ -258,7 +315,8 @@ void file_dialog::pre_show(window& window)
refresh_fileview();
window.keyboard_capture(find_widget<text_box>(&window, "filename", false, true));
//window.keyboard_capture(find_widget<text_box>(&window, "filename", false, true));
window.keyboard_capture(&file_textbox);
window.add_to_keyboard_chain(&filelist);
window.set_exit_hook(window::exit_hook::on_all, std::bind(&file_dialog::on_exit, this, std::placeholders::_1));
}

View file

@ -114,20 +114,26 @@ public:
file_dialog& set_filename(const std::string& value);
/**
* Sets the default file extension for file names in save mode.
* Sets allowed file extensions for file names in save mode.
*
* When this is set to a non-empty string and save mode is active, selecting
* file entries will cause their name portions to be highlighted in the name
* text box if their extensions match the provided template, and any time the
* text box is cleared it will position the cursor before the extension as a
* hint for the user.
* hint for the user. Additionally, the user will not be able to save the file
* with a wrong extension if this is set.
*
* In case of multiple extension, the first set extension is the default.
*
* The value provided to this method should be preceded by a dot if
* applicable (e.g. ".cfg").
*/
file_dialog& set_extension(const std::string& value)
{
extension_ = value;
if (extension_.empty()) {
extension_ = value;
}
extensions_.push_back(value);
return *this;
}
@ -206,6 +212,8 @@ private:
bool read_only_;
bool save_mode_;
std::vector<std::string> extensions_;
std::vector<std::string> dir_files_;
std::vector<std::string> dir_subdirs_;
@ -257,6 +265,11 @@ private:
bool process_submit_common(const std::string& name);
/**
* Check if the filename is valid and disable save button if invalid
*/
void check_filename();
/**
* Updates the bookmarks bar state to reflect the internal state.
*/

View file

@ -119,6 +119,7 @@ protected:
update_layout();
}
public:
/** Inherited from text_box_base. */
void goto_end_of_line(const bool select = false) override
{
@ -147,6 +148,7 @@ protected:
update_layout();
}
private:
/** Inherited from text_box_base. */
void paste_selection(const bool mouse) override
{

View file

@ -68,6 +68,7 @@ void scroll_text::set_label(const t_string& label)
if(resize_needed && get_size() != point()) {
place(get_origin(), get_size());
}
widget->goto_start_of_data();
}
}

View file

@ -105,17 +105,18 @@ void tab_container::add_tab_entry(const widget_data row)
void tab_container::select_tab(unsigned index)
{
unsigned count = get_tab_count();
if (index < count) {
if (index < get_tab_count()) {
get_internal_list().select_row(index);
generator_->select_item(index, true);
}
}
void tab_container::change_selection() {
select_tab(get_internal_list().get_selected_row());
select_tab(get_active_tab_index());
place(get_origin(), get_size());
queue_redraw();
fire(event::NOTIFY_MODIFIED, *this, nullptr);
}
// }---------- DEFINITION ---------{

View file

@ -50,9 +50,25 @@ public:
void select_tab(unsigned index);
unsigned get_tab_count() {
unsigned get_active_tab_index() {
return get_internal_list().get_selected_row();
}
unsigned get_tab_count() const {
return builders_.size();
}
grid* get_tab_grid(unsigned i)
{
assert(generator_);
return &generator_->item(i);
}
const grid* get_tab_grid(unsigned i) const
{
assert(generator_);
return &generator_->item(i);
}
private:
/**
* Possible states of the widget.

View file

@ -180,8 +180,8 @@ constexpr std::array<hotkey_command_temp, HOTKEY_NULL - 1> master_hotkey_list {{
{ HOTKEY_EDITOR_PARTIAL_UNDO, "editor-partial-undo", N_("Partial Undo"), false, scope_editor, HKCAT_SCENARIO, "" },
{ HOTKEY_EDITOR_MAP_NEW, "editor-map-new", N_("New Map"), false, scope_editor, HKCAT_SCENARIO, "" },
{ HOTKEY_EDITOR_SCENARIO_NEW, "editor-scenario-new", N_("New Scenario"), false, scope_editor, HKCAT_SCENARIO, "" },
{ HOTKEY_EDITOR_MAP_LOAD, "editor-map-load", N_("Load Map"), false, scope_editor, HKCAT_MAP, "" },
{ HOTKEY_EDITOR_MAP_SAVE, "editor-map-save", N_("Save Map"), false, scope_editor, HKCAT_MAP, "" },
{ HOTKEY_EDITOR_MAP_LOAD, "editor-map-load", N_("Load Map/Scenario"), false, scope_editor, HKCAT_MAP, "" },
{ HOTKEY_EDITOR_MAP_SAVE, "editor-map-save", N_("Save"), false, scope_editor, HKCAT_MAP, "" },
{ HOTKEY_EDITOR_MAP_SAVE_AS, "editor-map-save-as", N_("Save Map As"), false, scope_editor, HKCAT_MAP, "" },
{ HOTKEY_EDITOR_SCENARIO_SAVE_AS, "editor-scenario-save-as", N_("Save Scenario As"), false, scope_editor, HKCAT_SCENARIO, "" },
{ HOTKEY_EDITOR_MAP_SAVE_ALL, "editor-map-save-all", N_("Save All Maps"), false, scope_editor, HKCAT_MAP, "" },
@ -272,8 +272,10 @@ constexpr std::array<hotkey_command_temp, HOTKEY_NULL - 1> master_hotkey_list {{
{ HOTKEY_EDITOR_PBL, "editor-pbl", N_("Add-on Publishing Editor"), false, scope_editor, HKCAT_GENERAL, "" },
{ HOTKEY_EDITOR_CHANGE_ADDON_ID, "editor-addon-id", N_("Change Add-on ID"), false, scope_editor, HKCAT_GENERAL, "" },
{ HOTKEY_EDITOR_SELECT_ADDON, "editor-addon-select", N_("Select active Add-on"), false, scope_editor, HKCAT_GENERAL, "" },
{ HOTKEY_EDITOR_OPEN_ADDON, "editor-addon-open", N_("Open Add-on folder"), false, scope_editor, HKCAT_GENERAL, "" },
{ HOTKEY_EDITOR_SCENARIO_EDIT, "editor-scenario-edit", N_("Edit Scenario"), false, scope_editor, HKCAT_SCENARIO, "" },
{ HOTKEY_EDITOR_SCENARIO_EDIT, "editor-scenario-edit", N_("Edit Scenario Settings"), false, scope_editor, HKCAT_SCENARIO, "" },
{ HOTKEY_EDITOR_SIDE_EDIT, "editor-side-edit", N_("Edit Side"), false, scope_editor, HKCAT_SCENARIO, "" },
{ HOTKEY_EDITOR_SIDE_REMOVE, "editor-side-remove", N_("Remove Side"), false, scope_editor, HKCAT_SCENARIO, "" },

View file

@ -193,6 +193,8 @@ enum HOTKEY_COMMAND {
// Addons
HOTKEY_EDITOR_PBL,
HOTKEY_EDITOR_CHANGE_ADDON_ID,
HOTKEY_EDITOR_SELECT_ADDON,
HOTKEY_EDITOR_OPEN_ADDON,
// Scenario
HOTKEY_EDITOR_SCENARIO_EDIT,

View file

@ -1434,7 +1434,7 @@ template<>
struct dialog_tester<tod_new_schedule>
{
std::string id = "id";
std::string name = "name";
t_string name = "name";
dialog_tester() {}
tod_new_schedule* create()
{

View file

@ -1592,6 +1592,7 @@ bool unit::get_attacks_changed() const
}
return false;
}
void unit::write(config& cfg, bool write_all) const
{
config back;
@ -1781,6 +1782,17 @@ bool unit::loyal() const
return utils::holds_alternative<upkeep_loyal>(upkeep_);
}
void unit::set_loyal(bool loyal)
{
if (loyal) {
upkeep_ = upkeep_loyal{};
overlays_.push_back("misc/loyal-icon.png");
} else {
upkeep_ = upkeep_full{};
overlays_.erase(std::remove(overlays_.begin(), overlays_.end(), "misc/loyal-icon.png"), overlays_.end());
}
}
int unit::defense_modifier(const t_translation::terrain_code & terrain) const
{
int def = movement_type_.defense_modifier(terrain);

View file

@ -1282,6 +1282,8 @@ public:
/** Gets whether this unit is loyal - ie, it costs no upkeep. */
bool loyal() const;
void set_loyal(bool loyal);
/** Gets whether this unit is fearless - ie, unaffected by time of day. */
bool is_fearless() const
{