/* * Copyright 2016 MovingBlocks * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.terasology.rendering.nui.layers.mainMenu.settings; import com.google.common.base.Function; import com.google.common.base.Functions; import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.google.common.math.DoubleMath; import org.terasology.utilities.Assets; import org.terasology.assets.ResourceUrn; import org.terasology.config.Config; import org.terasology.engine.SimpleUri; import org.terasology.i18n.TranslationProject; import org.terasology.i18n.TranslationSystem; import org.terasology.registry.In; import org.terasology.rendering.assets.texture.Texture; import org.terasology.rendering.assets.texture.TextureUtil; import org.terasology.rendering.nui.Color; import org.terasology.rendering.nui.CoreScreenLayer; import org.terasology.rendering.nui.WidgetUtil; import org.terasology.rendering.nui.animation.MenuAnimationSystems; import org.terasology.rendering.nui.databinding.DefaultBinding; import org.terasology.rendering.nui.databinding.ReadOnlyBinding; import org.terasology.rendering.nui.widgets.UIButton; import org.terasology.rendering.nui.widgets.UIDropdownScrollable; import org.terasology.rendering.nui.widgets.UIImage; import org.terasology.rendering.nui.widgets.UISlider; import org.terasology.rendering.nui.widgets.UIText; import java.math.RoundingMode; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Collections; public class PlayerSettingsScreen extends CoreScreenLayer { public static final ResourceUrn ASSET_URI = new ResourceUrn("engine:PlayerMenuScreen"); @In private Config config; @In private TranslationSystem translationSystem; private final List<Color> colors = CieCamColors.L65C65; /** * Remove language x from this languagesExcluded table when it is ready for testing */ private final Locale[] languagesExcluded = {Locale.forLanguageTag("zh"), // TODO: Chinese symbols not yet available Locale.forLanguageTag("hi"), // TODO: Hindi (Indian) symbols not yet available Locale.forLanguageTag("ar"), // TODO: Arabic symbols not yet available, no translated entries yet Locale.forLanguageTag("ko"), // TODO: Korean symbols not yet available Locale.forLanguageTag("fa")}; // TODO: Farsi (Persian) symbols not yet available private UIText nametext; private UISlider slider; private UISlider heightSlider; private UISlider eyeHeightSlider; private UIImage img; private UIDropdownScrollable<Locale> language; @Override public void onOpened() { super.onOpened(); if (nametext != null) { nametext.setText(config.getPlayer().getName()); } if (slider != null) { Color color = config.getPlayer().getColor(); slider.bindValue(new NotifyingBinding(findClosestIndex(color))); } if (heightSlider != null) { heightSlider.bindValue(new NotifyingBinding(config.getPlayer().getHeight())); } if (eyeHeightSlider != null) { eyeHeightSlider.bindValue(new NotifyingBinding(config.getPlayer().getEyeHeight())); } if (language != null) { language.setSelection(config.getSystem().getLocale()); } updateImage(); } @Override public void initialise() { setAnimationSystem(MenuAnimationSystems.createDefaultSwipeAnimation()); nametext = find("playername", UIText.class); if (nametext != null) { nametext.setTooltipDelay(0); nametext.bindTooltipString(new ReadOnlyBinding<String>() { @Override public String get() { return validateScreen(); } }); } img = find("image", UIImage.class); if (img != null) { ResourceUrn uri = TextureUtil.getTextureUriForColor(Color.WHITE); Texture tex = Assets.get(uri, Texture.class).get(); img.setImage(tex); } slider = find("tone", UISlider.class); if (slider != null) { slider.setIncrement(0.01f); Function<Object, String> constant = Functions.constant(" "); // ensure a certain width slider.setLabelFunction(constant); } heightSlider = find("height", UISlider.class); if (heightSlider != null) { heightSlider.setMinimum(1.5f); heightSlider.setIncrement(0.1f); heightSlider.setRange(0.5f); heightSlider.setPrecision(1); } eyeHeightSlider = find("eye-height", UISlider.class); if (eyeHeightSlider != null) { eyeHeightSlider.setMinimum(0.5f); eyeHeightSlider.setIncrement(0.1f); eyeHeightSlider.setRange(1f); eyeHeightSlider.setPrecision(1); } language = find("language", UIDropdownScrollable.class); if (language != null) { SimpleUri menuUri = new SimpleUri("engine:menu"); TranslationProject menuProject = translationSystem.getProject(menuUri); List<Locale> locales = new ArrayList<>(menuProject.getAvailableLocales()); for (Locale languageExcluded : languagesExcluded) { locales.remove(languageExcluded); } Collections.sort(locales, ((Object o1, Object o2) -> (o1.toString().compareTo(o2.toString())))); language.setOptions(Lists.newArrayList(locales)); language.setVisibleOptions(5); // Set maximum number of options visible for scrolling language.setOptionRenderer(new LocaleRenderer(translationSystem)); } WidgetUtil.trySubscribe(this, "close", button -> triggerBackAnimation()); UIButton okButton = find("ok", UIButton.class); if (okButton != null) { okButton.subscribe(button -> { savePlayerSettings(); triggerBackAnimation(); }); okButton.bindEnabled(new ReadOnlyBinding<Boolean>() { @Override public Boolean get() { return Strings.isNullOrEmpty(validateScreen()); } }); okButton.setTooltipDelay(0); okButton.bindTooltipString(new ReadOnlyBinding<String>() { @Override public String get() { return validateScreen(); } }); } } private String validateScreen() { if (nametext != null && Strings.isNullOrEmpty(nametext.getText())) { return translationSystem.translate("${engine:menu#missing-name-message}"); } return null; } private float findClosestIndex(Color color) { int best = 0; float minDist = Float.MAX_VALUE; for (int i = 0; i < colors.size(); i++) { Color other = colors.get(i); float dr = other.rf() - color.rf(); float dg = other.gf() - color.gf(); float db = other.bf() - color.bf(); // there are certainly smarter ways to measure color distance, // but Euclidean distance is good enough for the purpose float dist = dr * dr + dg * dg + db * db; if (dist < minDist) { minDist = dist; best = i; } } float max = colors.size() - 1; return best / max; } private Color findClosestColor(float findex) { int index = DoubleMath.roundToInt(findex * (colors.size() - 1), RoundingMode.HALF_UP); Color color = colors.get(index); return color; } private void updateImage() { Color color = getColor(); if (img != null) { img.setTint(color); } } private Color getColor() { if (slider != null) { float index = slider.getValue(); return findClosestColor(index); } else { return config.getPlayer().getColor(); } } private Float getHeight() { if (heightSlider != null) { float index = heightSlider.getValue(); return index; } else { return config.getPlayer().getHeight(); } } private Float getEyeHeight() { if (eyeHeightSlider != null) { float index = eyeHeightSlider.getValue(); return index; } else { return config.getPlayer().getEyeHeight(); } } private void savePlayerSettings() { Color color = getColor(); config.getPlayer().setColor(color); Float height = getHeight(); config.getPlayer().setHeight(height); Float eyeHeight = getEyeHeight(); config.getPlayer().setEyeHeight(eyeHeight); if (nametext != null) { config.getPlayer().setName(nametext.getText()); } if (!config.getSystem().getLocale().equals(language.getSelection())) { config.getSystem().setLocale(language.getSelection()); getManager().invalidate(); } } @Override public boolean isLowerLayerVisible() { return false; } /** * Calls update() in parent class when the slider value changes */ private final class NotifyingBinding extends DefaultBinding<Float> { private NotifyingBinding(Float value) { super(value); } @Override public void set(Float v) { super.set(v); updateImage(); } } }