using System;
using System.IO;
using Gtk;
using UI = Gtk.Builder.ObjectAttribute;
public class MapWindow : IDisposable
{
[UI] private DrawingArea MapArea = null;
[UI] private Label MapTitleLabel = null;
[UI] private Button MapBackButton = null;
[UI] private Label MapCaseLabel = null;
[UI] private RadioButton BodySkeletonRadio = null;
[UI] private RadioButton BodyJacketRadio = null;
[UI] private ComboBoxText JacketSizeCombo = null;
[UI] private RadioButton ViewFrontRadio = null;
[UI] private RadioButton ViewBackRadio = null;
[UI] private RadioButton ViewRightRadio = null;
[UI] private RadioButton ViewLeftRadio = null;
[UI] private CheckButton HideCircleCheck = null;
[UI] private CheckButton BlackAudioCheck = null;
[UI] private Button SoundTestButton = null;
[UI] private TextView MapLogView = null;
[UI] private Box MapControlSlots = null;
private readonly Language _lang;
private readonly SoundLooper _sound = new SoundLooper();
private Gdk.Pixbuf _body;
private Gdk.Pixbuf _map;
private const double MapAlpha = 0.7;
public event EventHandler BackRequested;
public MapWindow(Builder builder, Language language)
{
builder.Autoconnect(this);
_lang = language;
MapArea.Drawn += OnMapDrawn;
MapBackButton.Clicked += OnBackClicked;
_lang.Register("MapBackButton", MapBackButton);
_lang.RegisterDynamic("MapTitleLabel", MapTitleLabel);
_sound.Log += msg => Logger.Write("sound", msg);
}
/// <summary>Called when a disease is picked. Loads images, starts the loop.</summary>
public void ShowCase(string title, string bodyPath, string mapPath, string soundPath)
{
MapTitleLabel.Text = title ?? "";
DisposePixbufs();
_body = LoadPixbuf(bodyPath, false);
_map = LoadPixbuf(mapPath, true); // true = key out black
Logger.Write("case", "open: " + title + " | map=" + mapPath + " | sound=" + soundPath);
MapArea.QueueDraw();
_sound.Start(soundPath);
}
/// <summary>Kills audio without touching the images. Call from OnBackClicked.</summary>
public void StopSession()
{
_sound.Stop();
Logger.Write("case", "closed");
}
private void OnBackClicked(object sender, EventArgs e)
{
StopSession();
var h = BackRequested;
if (h != null) h(this, EventArgs.Empty);
}
private void OnMapDrawn(object o, DrawnArgs args)
{
var cr = args.Cr;
int w = MapArea.AllocatedWidth;
int h = MapArea.AllocatedHeight;
DrawFitted(cr, _body, w, h, 1.0);
DrawFitted(cr, _map, w, h, MapAlpha);
args.RetVal = true;
}
private static void DrawFitted(Cairo.Context cr, Gdk.Pixbuf pb, int w, int h, double alpha)
{
if (pb == null) return;
double s = Math.Min((double)w / pb.Width, (double)h / pb.Height);
cr.Save();
cr.Translate((w - pb.Width * s) / 2, (h - pb.Height * s) / 2);
cr.Scale(s, s);
Gdk.CairoHelper.SetSourcePixbuf(cr, pb, 0, 0);
cr.PaintWithAlpha(alpha);
cr.Restore();
}
private static Gdk.Pixbuf LoadPixbuf(string path, bool keyOutBlack)
{
if (string.IsNullOrEmpty(path) || !File.Exists(path))
{
// Console.WriteLine("[MapWindow] image not found: " + path);
Logger.Write("map", "image not found: " + path);
return null;
}
try
{
var pb = new Gdk.Pixbuf(path);
if (!keyOutBlack) return pb;
var keyed = pb.AddAlpha(true, 0, 0, 0); // == MakeTransparent(Color.Black)
pb.Dispose();
return keyed;
}
catch (Exception ex)
{
// Console.WriteLine("[MapWindow] load failed " + path + ": " + ex.Message);
Logger.Write("map", "image not found: " + path);
return null;
}
}
private void DisposePixbufs()
{
if (_body != null) { _body.Dispose(); _body = null; }
if (_map != null) { _map.Dispose(); _map = null; }
}
public void Dispose()
{
_sound.Dispose();
DisposePixbufs();
}
}