diff --git a/ZATACKA.html b/ZATACKA.html
index 029d788..8367950 100644
--- a/ZATACKA.html
+++ b/ZATACKA.html
@@ -63,7 +63,7 @@
Achtung, die Kurve!
-
+
-
@@ -90,6 +90,7 @@
Achtung, die Kurve!
+
@@ -102,6 +103,10 @@ Achtung, die Kurve!
+
@@ -135,6 +140,7 @@ Achtung, die Kurve!
+
diff --git a/Zatacka.css b/Zatacka.css
index 55642fe..da1760b 100644
--- a/Zatacka.css
+++ b/Zatacka.css
@@ -34,43 +34,61 @@ a:hover, a:focus, a:active {
text-decoration: none;
}
-input[type="checkbox"] {
+input[type="checkbox"],
+input[type="radio"] {
display: none;
}
/* Checkbox and label: */
-input[type="checkbox"] + label {
- cursor: pointer;
- opacity: 0.75;
+input[type="checkbox"] + label,
+input[type="radio"] + label {
padding-left: 18px;
position: relative;
}
-/* Checkbox and label on hover: */
-input[type="checkbox"] + label:hover,
-input[type="checkbox"] + label:focus,
-input[type="checkbox"] + label:active {
- opacity: 1;
-}
-
/* Actual checkbox: */
-input[type="checkbox"] + label::before {
- border: 1px white solid;
+input[type="checkbox"] + label::before,
+input[type="radio"] + label::before {
+ background-position: center center;
+ background-repeat: no-repeat;
box-sizing: border-box;
content: "";
display: inline-block;
height: 12px;
left: 0;
position: absolute;
- top: 1px;
+ top: 2px;
width: 12px;
}
+input[type="checkbox"] + label::before {
+ border: 1px white solid;
+}
+
+input[type="radio"] + label::before {
+ background-image: url("resources/kurve-radio-button.png");
+}
+
/* Actual checkbox when checked: */
input[type="checkbox"]:checked + label::before {
background-image: url("resources/kurve-checkbox-tickmark.png");
- background-position: center center;
- background-repeat: no-repeat;
+}
+
+input[type="radio"]:checked + label::before {
+ background-image: url("resources/kurve-radio-button-checked.png");
+}
+
+input[type="checkbox"] + label,
+input[type="radio"] + label {
+ padding-top: 1px;
+ padding-bottom: 1px;
+}
+
+/* Checkbox and label on hover: */
+input[type="checkbox"] + label,
+input[type="radio"] + label,
+select {
+ cursor: pointer;
}
.button {
@@ -131,6 +149,24 @@ input[type="checkbox"]:checked + label::before {
cursor: none;
}
+.icon-button {
+ background-image: url("resources/kurve-icons.png");
+ cursor: pointer;
+ height: 16px;
+ opacity: 0.75;
+ width: 16px;
+}
+
+.icon-button:hover, .icon-button:focus, .icon-button:active {
+ opacity: 1;
+}
+
+.corner {
+ position: absolute;
+ right: 16px;
+ top: 16px;
+}
+
#debug {
background-color: black;
border: 1px white solid;
@@ -185,6 +221,10 @@ input[type="checkbox"]:checked + label::before {
border-color: #515151;
}
+.flex {
+ display: flex;
+}
+
.overlay {
display: block;
height: 100%;
@@ -195,6 +235,10 @@ input[type="checkbox"]:checked + label::before {
box-sizing: border-box;
}
+.hidden {
+ display: none;
+}
+
.unobtrusive {
pointer-events: none;
}
@@ -204,14 +248,15 @@ input[type="checkbox"]:checked + label::before {
overflow: hidden;
}
-#lobby.hidden, #KONEC_HRY.hidden {
- display: none;
+#lobby {
+ padding-left: 81px;
+ padding-top: 50px;
+ padding-bottom: 130px; /* 130 = 480 - 7 * 50, where 50 is the total height of each player's controls and 7 is 6 players plus 1 for margin */
}
#lobby #controls {
+ display: inline-block;
list-style-type: none;
- margin-left: 80px;
- margin-top: 50px;
}
#lobby #controls li {
@@ -229,13 +274,13 @@ input[type="checkbox"]:checked + label::before {
}
#lobby #controls .ready {
+ visibility: hidden;
background-image: url("resources/kurve-lobby-controls-ready.png");
- display: none;
width: 80px;
}
#lobby #controls .ready.active {
- display: block;
+ visibility: visible;
}
#lobby #controls .red.controls { background-position: 0px 0px; }
@@ -251,8 +296,77 @@ input[type="checkbox"]:checked + label::before {
#lobby #controls .blue.controls { background-position: 0px -250px; }
#lobby #controls .blue.ready { background-position: -160px -250px; }
-#lobby footer {
+#button-show-settings {
+ background-position: 0 -16px;
+}
+
+#button-hide-settings {
+ background-position: 0 0;
+}
+
+#settings {
+ background-color: rgba(0, 0, 0, 0.95);
+ padding: 50px 80px 50px 80px;
+}
+
+#settings-form > div {
+ box-sizing: border-box;
+ margin: 12px 0;
+ opacity: 0.6;
+}
+
+#settings-form > div:hover {
+ opacity: 1;
+}
+
+#settings-form > div:hover .description {
+ visibility: visible;
+}
+
+#settings-form fieldset {
+ border: 1px solid white;
+ padding: 2px 8px 6px 8px;
+}
+
+#settings-form fieldset legend {
+ padding: 0 4px;
+}
+
+#settings-form input[type="checkbox"] + label {
+ margin-left: 13px; /* to align with fieldset content */
+}
+
+#settings-form fieldset input[type="radio"] + label {
+ margin-left: 4px; /* to align with legend */
+}
+
+#settings-form label {
+ display: inline-block;
+}
+
+#settings-form .description {
+ box-sizing: border-box;
+ bottom: 0;
+ font-size: 0.75em;
+ height: 50px;
+ left: 0;
+ opacity: 0.8;
padding: 0 80px;
+ position: absolute;
+ visibility: hidden;
+ width: 100%;
+}
+
+#settings-form select {
+ background: black;
+ border: 1px solid white;
+ color: white;
+ margin-top: 2px;
+ width: 219px;
+}
+
+#settings-form input[type="radio"] + label {
+ display: block;
}
#messages {
@@ -274,6 +388,15 @@ input[type="checkbox"]:checked + label::before {
color: #C3C300;
}
+#messages.hints-none .message,
+#messages.hints-warnings-only .message {
+ display: none;
+}
+
+#messages.hints-warnings-only .message.warning {
+ display: block;
+}
+
.canvasHeight {
height: 480px;
}
diff --git a/index.html b/index.html
index 089a101..b4f78c4 100644
--- a/index.html
+++ b/index.html
@@ -64,6 +64,7 @@ Achtung, die Kurve!
+
diff --git a/js/GUIController.js b/js/GUIController.js
index 6a904fb..40c8cc9 100644
--- a/js/GUIController.js
+++ b/js/GUIController.js
@@ -2,10 +2,6 @@
function GUIController(cfg) {
- const CURSOR_VISIBLE = "visible";
- const CURSOR_HIDDEN_ON_CANVAS = "hidden_on_canvas";
- const CURSOR_HIDDEN = "hidden";
-
const config = cfg;
const lobby = byID("lobby");
const controls = byID("controls");
@@ -16,6 +12,8 @@ function GUIController(cfg) {
const results = byID("results");
const KONEC_HRY = byID("KONEC_HRY");
const messagesContainer = byID("messages");
+ const settingsContainer = byID("settings");
+ const settingsForm = byID("settings-form");
const ORIGINAL_LEFT_WIDTH = left.offsetWidth;
@@ -52,14 +50,10 @@ function GUIController(cfg) {
function setCursorBehavior(behavior) {
switch (behavior) {
- case CURSOR_VISIBLE:
+ case STRINGS.cursor_visible:
document.body.classList.remove(STRINGS.class_nocursor);
break;
- case CURSOR_HIDDEN_ON_CANVAS:
- canvas_main.classList.add(STRINGS.class_nocursor);
- canvas_overlay.classList.add(STRINGS.class_nocursor);
- break;
- case CURSOR_HIDDEN:
+ case STRINGS.cursor_hidden:
document.body.classList.add(STRINGS.class_nocursor);
break;
default:
@@ -67,8 +61,66 @@ function GUIController(cfg) {
}
}
- function resetCursorBehavior() {
- setCursorBehavior(CURSOR_VISIBLE);
+ function settingsEntryHTMLElement(preference, preferenceValue) {
+ if (!preference instanceof Preference) {
+ throw new TypeError(`${preference} is not a preference.`);
+ }
+
+ // Common
+ const div = document.createElement("div");
+ const label = document.createElement("label");
+ label.textContent = preference.label;
+ label.setAttribute("for", `${STRINGS.html_name_preference_prefix}${preference.key}`);
+ const description = document.createElement("aside");
+ description.textContent = preference.description;
+ description.classList.add(STRINGS.class_description);
+
+ // Boolean
+ if (preference instanceof BooleanPreference) {
+ const input = document.createElement("input");
+ input.type = "checkbox";
+ input.dataset.key = preference.key;
+ input.id = STRINGS.html_name_preference_prefix + preference.key;
+ input.checked = preferenceValue === true;
+ div.appendChild(input);
+ div.appendChild(label);
+ }
+
+ // Multichoice
+ else if (preference instanceof MultichoicePreference) {
+ const fieldset = document.createElement("fieldset");
+ const legend = document.createElement("legend");
+ legend.textContent = preference.label;
+ fieldset.appendChild(legend);
+ preference.values.forEach((value, index) => {
+ const id = STRINGS.html_name_preference_prefix + preference.key + "-" + preference.values[index];
+ const radioButton = document.createElement("input");
+ radioButton.type = "radio";
+ radioButton.id = id;
+ radioButton.name = STRINGS.html_name_preference_prefix + preference.key;
+ radioButton.value = value;
+ radioButton.dataset.key = preference.key;
+ radioButton.checked = preferenceValue === value;
+ const radioButtonLabel = document.createElement("label");
+ radioButtonLabel.textContent = preference.labels[index];
+ radioButtonLabel.setAttribute("for", id);
+ fieldset.appendChild(radioButton);
+ fieldset.appendChild(radioButtonLabel);
+ });
+ div.appendChild(fieldset);
+ }
+
+ // Range
+ else if (preference instanceof RangePreference) {
+ div.appendChild(label);
+ const input = document.createElement("input");
+ input.type = "number";
+ input.name = STRINGS.html_name_preference_prefix + preference.key;
+ div.appendChild(input);
+ }
+
+ div.appendChild(description);
+ return div;
}
@@ -115,7 +167,7 @@ function GUIController(cfg) {
resetScoreboard();
resetResults();
allPlayersUnready();
- resetCursorBehavior();
+ setCursorBehavior(STRINGS.cursor_visible);
}
function konecHry() {
@@ -138,6 +190,47 @@ function GUIController(cfg) {
updateMessages(currentMessages);
}
+ function showSettings() {
+ settings.classList.remove(STRINGS.class_hidden);
+ }
+
+ function hideSettings() {
+ settings.classList.add(STRINGS.class_hidden);
+ }
+
+ function updateSettingsForm(preferencesWithData) {
+ flush(settingsForm);
+ preferencesWithData.forEach((preferenceWithData) => {
+ settingsForm.appendChild(settingsEntryHTMLElement(preferenceWithData.preference, preferenceWithData.value));
+ });
+ }
+
+ function parseSettingsForm() {
+ const newSettings = [];
+ // elements:
+ const inputs = settingsForm.querySelectorAll("input");
+ Array.from(inputs).forEach((input) => {
+ if (input.type === "checkbox") {
+ // checkbox
+ newSettings.push({ key: input.dataset.key, value: input.checked });
+ } else if (input.type === "radio") {
+ // radio
+ if (input.checked === true) {
+ newSettings.push({ key: input.dataset.key, value: input.value });
+ }
+ } else {
+ // text, number etc
+ newSettings.push({ key: input.dataset.key, value: input.value.toString() });
+ }
+ });
+ //