Newer
Older
EARS-LINUX / program / MainWindow.cs
using System;
using System.Collections.Generic;
using System.IO;
using Gtk;
using UI = Gtk.Builder.ObjectAttribute;

public class MainWindow : Window
{
    [UI] private Button Option1Button = null;
    [UI] private Button Option2Button = null;
    [UI] private Button Option3Button = null;
    [UI] private Switch LanguageSwitch = null;
    [UI] private Label LanguageLabel = null;
    [UI] private Button CloseButton = null;

    private CssProvider _scaleCssProvider;
    private CssProvider _languageCssProvider;
    private int _lastAppliedWidth = -1;

    private const int BaseWidth = 1920;
    private const int BaseHeight = 1080;

    private const string EngCssPath = "lang_eng.css";
    private const string JpnCssPath = "lang_jpn.css";

    private Dictionary<string, string> _engText;
    private Dictionary<string, string> _jpnText;
    private Dictionary<string, Button> _buttonsById;

    public MainWindow() : this(CreateBuilder()) { }

    private static Builder CreateBuilder()
    {
        var builder = new Builder();
        builder.AddFromFile("homepage.glade");
        return builder;
    }

    private MainWindow(Builder builder) : base(builder.GetObject("SplashWindow").Handle)
    {
        builder.Autoconnect(this);

        _scaleCssProvider = new CssProvider();
        _languageCssProvider = new CssProvider();

        StyleContext.AddProviderForScreen(Gdk.Screen.Default, _scaleCssProvider, 600);
        StyleContext.AddProviderForScreen(Gdk.Screen.Default, _languageCssProvider, 600);

        this.Fullscreen();

        Option1Button.Clicked += OnNormalSessionClicked;
        Option2Button.Clicked += OnPositionRecordingClicked;
        Option3Button.Clicked += OnExamModeClicked;
        CloseButton.Clicked += OnCloseClicked;
        LanguageSwitch.AddNotification("active", OnLanguageSwitchNotify);

        DeleteEvent += OnDeleteEvent;
        SizeAllocated += OnWindowSizeAllocated;

        _buttonsById = new Dictionary<string, Button>
        {
            { "Option1Button", Option1Button },
            { "Option2Button", Option2Button },
            { "Option3Button", Option3Button },
            { "CloseButton", CloseButton },
        };

        // CSS ID selectors (#Option1Button etc.) need the widget Name set explicitly
        foreach (var kvp in _buttonsById)
            kvp.Value.Name = kvp.Key;

        _engText = LoadButtonText("info_eng.csv");
        _jpnText = LoadButtonText("info_jpn.csv");

        ApplyLanguage(LanguageSwitch.Active);
    }

    private Dictionary<string, string> LoadButtonText(string path)
    {
        var result = new Dictionary<string, string>();

        if (!File.Exists(path))
        {
            Console.WriteLine($"Warning: text file not found: {path}");
            return result;
        }

        var lines = File.ReadAllLines(path);
        for (int i = 1; i < lines.Length; i++) // skip header row
        {
            var line = lines[i].Trim();
            if (string.IsNullOrEmpty(line)) continue;

            var parts = line.Split(new[] { ',' }, 2); // split into max 2 pieces, in case text has commas
            if (parts.Length < 2) continue;

            result[parts[0]] = parts[1];
        }

        return result;
    }

    private void ApplyLanguage(bool isEnglish)
    {
        var text = isEnglish ? _engText : _jpnText;
        string cssPath = isEnglish ? EngCssPath : JpnCssPath;

        foreach (var kvp in _buttonsById)
        {
            if (text.TryGetValue(kvp.Key, out var buttonText))
                kvp.Value.Label = buttonText;
        }

        if (File.Exists(cssPath))
        {
            _languageCssProvider.LoadFromPath(cssPath);
        }
        else
        {
            Console.WriteLine($"Warning: CSS file not found: {cssPath}");
        }

        LanguageLabel.Text = isEnglish ? "あ" : "A";
    }
    private void OnWindowSizeAllocated(object o, SizeAllocatedArgs args)
    {
        int width = args.Allocation.Width;
        int height = args.Allocation.Height;

        if (width == _lastAppliedWidth) return;
        _lastAppliedWidth = width;

        double scaleX = (double)width / BaseWidth;
        double scaleY = (double)height / BaseHeight;
        double scale = Math.Min(scaleX, scaleY);

        ApplyScale(scale);
    }

    private void ApplyScale(double scale)
    {
        int fontSize   = Math.Max(10, (int)(20 * scale));
        int buttonPadV = Math.Max(4,  (int)(12 * scale));
        int buttonPadH = Math.Max(8,  (int)(24 * scale));

        string css = $@"
            grid, label, button, switch {{
                font-size: {fontSize}px;
            }}
            button {{
                padding: {buttonPadV}px {buttonPadH}px;
            }}
            switch {{
                min-width: {40 * scale}px;
                min-height: {24 * scale}px;
            }}
        ";

        _scaleCssProvider.LoadFromData(css);
    }

    private void OnDeleteEvent(object sender, DeleteEventArgs a)
    {
        Application.Quit();
        a.RetVal = true;
    }

    private void OnNormalSessionClicked(object sender, EventArgs e)
    {
        Console.WriteLine("Normal Session selected");
    }

    private void OnPositionRecordingClicked(object sender, EventArgs e)
    {
        Console.WriteLine("Position Recording Mode selected");
    }

    private void OnExamModeClicked(object sender, EventArgs e)
    {
        Console.WriteLine("Exam Mode selected");
    }

    private void OnCloseClicked(object sender, EventArgs e)
    {
        Application.Quit();
    }

    private void OnLanguageSwitchNotify(object o, GLib.NotifyArgs args)
    {
        ApplyLanguage(LanguageSwitch.Active);
    }
}