Skip to content

Commit 0a83846

Browse files
AzgaarCopilotCopilot
authored
QoL updates (#1391)
* feat: qol updates Co-authored-by: Copilot <copilot@github.com> * feat: add undo functionality and brush size controls for cultures, states, and religions Co-authored-by: Copilot <copilot@github.com> * fix: restore direct brush dragging functionality in heightmap editor * feat: add fill brush functionality to heightmap editor Co-authored-by: Copilot <copilot@github.com> * fix: improve fill brush error handling and enhance brush size change detection Co-authored-by: Copilot <copilot@github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
1 parent e13bc3e commit 0a83846

7 files changed

Lines changed: 257 additions & 53 deletions

File tree

public/modules/dynamic/editors/cultures-editor.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const $body = insertEditorHtml();
22
addListeners();
3+
let culturesManualHistory = [];
34

45
const cultureTypes = ["Generic", "River", "Lake", "Naval", "Nomadic", "Hunting", "Highland"];
56

@@ -51,9 +52,10 @@ function insertEditorHtml() {
5152
<button id="culturesHeirarchy" data-tip="Show cultures hierarchy tree" class="icon-sitemap"></button>
5253
<button id="culturesManually" data-tip="Manually re-assign cultures" class="icon-brush"></button>
5354
<div id="culturesManuallyButtons" style="display: none">
54-
<div data-tip="Change brush size. Shortcut: + to increase; to decrease" style="margin-block: 0.3em;">
55+
<div data-tip="Change brush size. Shortcuts: + / ] to increase; - / [ to decrease" style="margin-block: 0.3em;">
5556
<slider-input id="culturesBrush" min="1" max="100" value="15">Brush size:</slider-input>
5657
</div>
58+
<button id="culturesManuallyUndo" data-tip="Undo last brush stroke" class="icon-ccw"></button>
5759
<button id="culturesManuallyApply" data-tip="Apply assignment" class="icon-check"></button>
5860
<button id="culturesManuallyCancel" data-tip="Cancel assignment" class="icon-cancel"></button>
5961
</div>
@@ -83,6 +85,7 @@ function addListeners() {
8385
byId("culturesHeirarchy").on("click", showHierarchy);
8486
byId("culturesRecalculate").on("click", () => recalculateCultures(true));
8587
byId("culturesManually").on("click", enterCultureManualAssignent);
88+
byId("culturesManuallyUndo").on("click", undoCulturesManualAssignment);
8689
byId("culturesManuallyApply").on("click", applyCultureManualAssignent);
8790
byId("culturesManuallyCancel").on("click", () => exitCulturesManualAssignment());
8891
byId("culturesEditNamesBase").on("click", editNamesbase);
@@ -690,6 +693,7 @@ function enterCultureManualAssignent() {
690693
.on("touchmove mousemove", moveCultureBrush);
691694

692695
$body.querySelector("div").classList.add("selected");
696+
culturesManualHistory = [];
693697
}
694698

695699
function selectCultureOnLineClick(i) {
@@ -712,6 +716,7 @@ function selectCultureOnMapClick() {
712716

713717
function dragCultureBrush() {
714718
const radius = +culturesBrush.value;
719+
saveCulturesManualSnapshot();
715720

716721
d3.event.on("drag", () => {
717722
if (!d3.event.dx && !d3.event.dy) return;
@@ -774,6 +779,7 @@ function applyCultureManualAssignent() {
774779

775780
function exitCulturesManualAssignment(close) {
776781
customization = 0;
782+
culturesManualHistory = [];
777783
cults.select("#temp").remove();
778784
removeCircle();
779785
document.querySelectorAll("#culturesBottom > *").forEach(el => (el.style.display = "inline-block"));
@@ -791,6 +797,21 @@ function exitCulturesManualAssignment(close) {
791797
if (selected) selected.classList.remove("selected");
792798
}
793799

800+
function saveCulturesManualSnapshot() {
801+
const temp = cults.select("#temp").node();
802+
if (!temp) return;
803+
804+
culturesManualHistory.push(temp.innerHTML);
805+
if (culturesManualHistory.length > 100) culturesManualHistory.shift();
806+
}
807+
808+
function undoCulturesManualAssignment() {
809+
const temp = cults.select("#temp").node();
810+
if (!temp || !culturesManualHistory.length) return;
811+
812+
temp.innerHTML = culturesManualHistory.pop();
813+
}
814+
794815
function enterAddCulturesMode() {
795816
if (this.classList.contains("pressed")) return exitAddCultureMode();
796817

public/modules/dynamic/editors/religions-editor.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,15 @@ function insertEditorHtml() {
6666
6767
<button id="religionsManually" data-tip="Manually re-assign religions" class="icon-brush"></button>
6868
<div id="religionsManuallyButtons" style="display: none">
69-
<div data-tip="Change brush size. Shortcut: + to increase; to decrease" style="margin-block: 0.3em;">
69+
<div data-tip="Change brush size. Shortcuts: + or ] to increase; - or [ to decrease" style="margin-block: 0.3em;">
7070
<slider-input id="religionsBrush" min="1" max="100" value="15">Brush size:</slider-input>
7171
</div>
7272
<button id="religionsManuallyApply" data-tip="Apply assignment" class="icon-check"></button>
7373
<button id="religionsManuallyCancel" data-tip="Cancel assignment" class="icon-cancel"></button>
74+
<div data-tip="When enabled, only cells without religion can be painted" style="display: inline-block">
75+
<input id="religionsManuallyProtect" class="checkbox" type="checkbox" />
76+
<label for="religionsManuallyProtect" class="checkbox-label"><i>do not overwrite existing</i></label>
77+
</div>
7478
</div>
7579
<button id="religionsAdd" data-tip="Add a new religion. Hold Shift to add multiple" class="icon-plus"></button>
7680
<button id="religionsExport" data-tip="Download religions-related data" class="icon-download"></button>
@@ -174,8 +178,8 @@ function religionsEditorAddLines() {
174178
<div data-tip="Religion area" class="religionArea hide" style="width: 6em">${si(area) + unit}</div>
175179
<span data-tip="${populationTip}" class="icon-male hide"></span>
176180
<div data-tip="${populationTip}" class="religionPopulation hide pointer" style="width: 5em">${si(
177-
population
178-
)}</div>
181+
population
182+
)}</div>
179183
</div>`;
180184
continue;
181185
}
@@ -208,8 +212,8 @@ function religionsEditorAddLines() {
208212
<div data-tip="Religion area" class="religionArea hide" style="width: 6em">${si(area) + unit}</div>
209213
<span data-tip="${populationTip}" class="icon-male hide"></span>
210214
<div data-tip="${populationTip}" class="religionPopulation hide pointer" style="width: 5em">${si(
211-
population
212-
)}</div>
215+
population
216+
)}</div>
213217
${getExpansionColumns(r)}
214218
<span data-tip="Lock this religion" class="icon-lock${r.lock ? "" : "-open"} hide"></span>
215219
<span data-tip="Remove religion" class="icon-trash-empty hide"></span>
@@ -700,11 +704,13 @@ function changeReligionForSelection(selection) {
700704
const selected = $body.querySelector("div.selected");
701705
const religionNew = +selected.dataset.id;
702706
const color = pack.religions[religionNew].color || "#ffffff";
707+
const preventOverwrite = byId("religionsManuallyProtect")?.checked;
703708

704709
selection.forEach(function (i) {
705710
const exists = temp.select("polygon[data-cell='" + i + "']");
706711
const religionOld = exists.size() ? +exists.attr("data-religion") : pack.cells.religion[i];
707712
if (religionNew === religionOld) return;
713+
if (preventOverwrite && religionOld) return;
708714

709715
// change of append new element
710716
if (exists.size()) exists.attr("data-religion", religionNew).attr("fill", color);

public/modules/dynamic/editors/states-editor.js

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const $body = insertEditorHtml();
22
addListeners();
3+
let statesManualHistory = [];
34

45
export function open() {
56
closeDialogs("#statesEditor, .stable");
@@ -71,11 +72,16 @@ function insertEditorHtml() {
7172
7273
<button id="statesManually" data-tip="Manually re-assign states" class="icon-brush"></button>
7374
<div id="statesManuallyButtons" style="display: none">
74-
<div data-tip="Change brush size. Shortcut: + to increase; to decrease" style="margin-block: 0.3em;">
75+
<div data-tip="Change brush size. Shortcuts: + / ] to increase; - / [ to decrease" style="margin-block: 0.3em;">
7576
<slider-input id="statesBrush" min="1" max="100" value="15">Brush size:</slider-input>
7677
</div>
78+
<button id="statesManuallyUndo" data-tip="Undo last brush stroke" class="icon-ccw"></button>
7779
<button id="statesManuallyApply" data-tip="Apply assignment" class="icon-check"></button>
7880
<button id="statesManuallyCancel" data-tip="Cancel assignment" class="icon-cancel"></button>
81+
<div data-tip="When enabled, only neutral cells can be painted" style="display: inline-block">
82+
<input id="statesManuallyProtect" class="checkbox" type="checkbox" />
83+
<label for="statesManuallyProtect" class="checkbox-label"><i>do not overwrite existing</i></label>
84+
</div>
7985
</div>
8086
8187
<button id="statesAdd" data-tip="Add a new state. Hold Shift to add multiple" class="icon-plus"></button>
@@ -102,6 +108,7 @@ function addListeners() {
102108
byId("statesRandomize").on("click", randomizeStatesExpansion);
103109
byId("statesGrowthRate").on("input", () => recalculateStates(false));
104110
byId("statesManually").on("click", enterStatesManualAssignent);
111+
byId("statesManuallyUndo").on("click", undoStatesManualAssignment);
105112
byId("statesManuallyApply").on("click", applyStatesManualAssignent);
106113
byId("statesManuallyCancel").on("click", () => exitStatesManualAssignment(false));
107114
byId("statesAdd").on("click", enterAddStateMode);
@@ -249,8 +256,8 @@ function statesEditorAddLines() {
249256
<span data-tip="${populationTip}" class="icon-male hide"></span>
250257
<div data-tip="${populationTip}" class="statePopulation pointer hide" style="width: 5em">${si(population)}</div>
251258
<select data-tip="State type. Defines growth model. Click to change" class="cultureType ${hidden} show hide">${getTypeOptions(
252-
s.type
253-
)}</select>
259+
s.type
260+
)}</select>
254261
<span data-tip="State expansionism" class="icon-resize-full ${hidden} show hide"></span>
255262
<input data-tip="Expansionism (defines competitive size). Change to re-calculate states based on new value"
256263
class="statePower ${hidden} show hide" type="number" min="0" max="99" step=".1" value=${s.expansionism} />
@@ -771,12 +778,12 @@ function showStatesChart() {
771778
option === "area"
772779
? "Area: " + area
773780
: option === "rural"
774-
? "Rural population: " + si(rural)
775-
: option === "urban"
776-
? "Urban population: " + si(urban)
777-
: option === "burgs"
778-
? "Burgs number: " + d.data.burgs
779-
: "Population: " + si(rural + urban);
781+
? "Rural population: " + si(rural)
782+
: option === "urban"
783+
? "Urban population: " + si(urban)
784+
: option === "burgs"
785+
? "Burgs number: " + d.data.burgs
786+
: "Population: " + si(rural + urban);
780787

781788
statesInfo.innerHTML = /* html */ `${state}. ${value}`;
782789
stateHighlightOn(ev);
@@ -794,12 +801,12 @@ function showStatesChart() {
794801
this.value === "area"
795802
? d => d.area
796803
: this.value === "rural"
797-
? d => d.rural
798-
: this.value === "urban"
799-
? d => d.urban
800-
: this.value === "burgs"
801-
? d => d.burgs
802-
: d => d.rural + d.urban;
804+
? d => d.rural
805+
: this.value === "urban"
806+
? d => d.urban
807+
: this.value === "burgs"
808+
? d => d.burgs
809+
: d => d.rural + d.urban;
803810

804811
root.sum(value);
805812
node.data(treeLayout(root).leaves());
@@ -903,6 +910,7 @@ function enterStatesManualAssignent() {
903910
.on("touchmove mousemove", moveStateBrush);
904911

905912
$body.querySelector("div").classList.add("selected");
913+
statesManualHistory = [];
906914
}
907915

908916
function selectStateOnLineClick() {
@@ -926,6 +934,7 @@ function selectStateOnMapClick() {
926934

927935
function dragStateBrush() {
928936
const r = +statesBrush.value;
937+
saveStatesManualSnapshot();
929938

930939
d3.event.on("drag", () => {
931940
if (!d3.event.dx && !d3.event.dy) return;
@@ -945,11 +954,13 @@ function changeStateForSelection(selection) {
945954
const $selected = $body.querySelector("div.selected");
946955
const stateNew = +$selected.dataset.id;
947956
const color = pack.states[stateNew].color || "#ffffff";
957+
const preventOverwrite = byId("statesManuallyProtect")?.checked;
948958

949959
selection.forEach(function (i) {
950960
const exists = temp.select("polygon[data-cell='" + i + "']");
951961
const stateOld = exists.size() ? +exists.attr("data-state") : pack.cells.state[i];
952962
if (stateNew === stateOld) return;
963+
if (preventOverwrite && stateOld) return;
953964
if (i === pack.states[stateOld].center) return;
954965

955966
// change of append new element
@@ -1148,6 +1159,7 @@ function adjustProvinces(affectedProvinces) {
11481159

11491160
function exitStatesManualAssignment(close) {
11501161
customization = 0;
1162+
statesManualHistory = [];
11511163
statesBody.select("#temp").remove();
11521164
removeCircle();
11531165
document.querySelectorAll("#statesBottom > button").forEach(el => (el.style.display = "inline-block"));
@@ -1168,6 +1180,21 @@ function exitStatesManualAssignment(close) {
11681180
if (selected) selected.classList.remove("selected");
11691181
}
11701182

1183+
function saveStatesManualSnapshot() {
1184+
const temp = statesBody.select("#temp").node();
1185+
if (!temp) return;
1186+
1187+
statesManualHistory.push(temp.innerHTML);
1188+
if (statesManualHistory.length > 100) statesManualHistory.shift();
1189+
}
1190+
1191+
function undoStatesManualAssignment() {
1192+
const temp = statesBody.select("#temp").node();
1193+
if (!temp || !statesManualHistory.length) return;
1194+
1195+
temp.innerHTML = statesManualHistory.pop();
1196+
}
1197+
11711198
function enterAddStateMode() {
11721199
if (this.classList.contains("pressed")) {
11731200
exitAddStateMode();

0 commit comments

Comments
 (0)