using System; using System.IO; namespace DesertPaintLab { [System.ComponentModel.ToolboxItem(true)] public partial class CaptureView : Gtk.Bin { Reagent[] reagents = new Reagent[3]; PaintRecipe recipe = new PaintRecipe(); PaintColor expectedColor = new PaintColor(); PaintColor reactedColor = new PaintColor(); PlayerProfile profile = null; Gdk.Pixbuf screenBuffer = null; bool recordEnabled = true; bool isCaptured = false; public CaptureView(PlayerProfile profile, Gdk.Pixbuf screenBuffer) : base() { this.profile = profile; this.screenBuffer = screenBuffer; this.Build(); reagents[0] = null; reagents[1] = null; reagents[2] = null; if (unmodifiedSwatch != null) { unmodifiedSwatch.Clear(); } if (reactionSwatch != null) { reactionSwatch.Clear(); } PopulateDropDowns(); recipe.Reactions = profile.Reactions; } public PlayerProfile Profile { set { profile = value; PopulateDropDowns(); recipe.Reactions = profile.Reactions; UpdateIngredients(); // TODO: reset views } } public void DisableRecord() { recordEnabled = false; recordButton.Sensitive = false; } public void EnableRecord() { recordEnabled = true; if (isCaptured) { recordEnabled = true; } UpdateIngredients(); } public void PopulateDropDowns() { ReagentManager.PopulateReagents(ref ingredient1ComboBox); ReagentManager.PopulateReagents(ref ingredient2ComboBox); ReagentManager.PopulateReagents(ref ingredient3ComboBox); ingredient2ComboBox.Sensitive = false; ingredient3ComboBox.Sensitive = false; Gtk.TreeIter iter; ingredient1ComboBox.Model.IterNthChild(out iter, 0); ingredient1ComboBox.SetActiveIter(iter); ingredient2ComboBox.Model.IterNthChild(out iter, 0); ingredient2ComboBox.SetActiveIter(iter); ingredient3ComboBox.Model.IterNthChild(out iter, 0); ingredient3ComboBox.SetActiveIter(iter); } protected void SetExpectedColor(byte red, byte green, byte blue) { expectedColor.Red = red; expectedColor.Green = green; expectedColor.Blue = blue; unmodifiedSwatch.Color = expectedColor; } protected void SetExpectedColor(PaintColor color) { SetExpectedColor(color.Red, color.Green, color.Blue); } protected string GetSelectedReagentName(int reagentNum) { Gtk.ComboBox[] comboBox = { ingredient1ComboBox, ingredient2ComboBox, ingredient3ComboBox }; Gtk.ComboBox desired = comboBox[reagentNum-1]; Gtk.TreeIter selectIter; string reagentName = null; if (desired.GetActiveIter(out selectIter)) { reagentName = (string)desired.Model.GetValue(selectIter, 0); } if (reagentName != null && reagentName.Length == 0) { reagentName = null; } return reagentName; } protected void UpdateIngredients() { Reaction reaction1, reaction2; string reagentName; reagents[0] = null; reagents[1] = null; reagents[2] = null; bool reactionKnown = true; isCaptured = false; recordButton.Sensitive = false; clearReactionButton.Sensitive = false; clearReactionButton.Visible = false; recipe.Clear(); if ((reagentName = GetSelectedReagentName(1)) == null) { // Nothing selected as reagent 1 ingredient2ComboBox.Sensitive = false; ingredient3ComboBox.Sensitive = false; unmodifiedSwatch.Clear(); reactionSwatch.Clear(); captureButton.Sensitive = false; return; } recipe.AddReagent(reagentName); reagents[0] = ReagentManager.GetReagent(reagentName); ingredient2ComboBox.Sensitive = true; if ((reagentName = GetSelectedReagentName(2)) == null) { ingredient3ComboBox.Sensitive = false; recordButton.Sensitive = false; reactionKnown = false; reactionSwatch.Clear(); return; } recipe.AddReagent(reagentName); reagents[1] = ReagentManager.GetReagent(reagentName); ingredient3ComboBox.Sensitive = true; captureButton.Sensitive = true; reaction1 = profile.FindReaction(reagents[0], reagents[1]); // TODO: really should handle reagent0==reagent1 better if ((reaction1 != null) || (reagents[0] == reagents[1])) { clearReactionButton.Sensitive = recordEnabled; clearReactionButton.Visible = true; ingredient3ComboBox.Sensitive = true; if ((reagentName = GetSelectedReagentName(3)) != null) { clearReactionButton.Sensitive = false; clearReactionButton.Visible = false; recipe.AddReagent(reagentName); reagents[2] = ReagentManager.GetReagent(reagentName); if (!reactionKnown) { Gtk.MessageDialog md = new Gtk.MessageDialog((Gtk.Window)Toplevel, Gtk.DialogFlags.DestroyWithParent, Gtk.MessageType.Error, Gtk.ButtonsType.Ok, "To do a three-ingredient reaction test, " + "you must first recored the reaction of " + "the first two ingredients."); md.Run(); md.Destroy(); captureButton.Sensitive = false; } reaction1 = profile.FindReaction(reagents[0], reagents[2]); reaction2 = profile.FindReaction(reagents[1], reagents[2]); if (reactionKnown && (reaction1 == null) && (reaction2 == null)) { Gtk.MessageDialog md = new Gtk.MessageDialog((Gtk.Window)Toplevel, Gtk.DialogFlags.DestroyWithParent, Gtk.MessageType.Error, Gtk.ButtonsType.Ok, "To do a three-ingredient reaction test, " + "you must first record the reaction of " + "either the first or second ingredient " + "with the third ingredient."); md.Run(); md.Destroy(); captureButton.Sensitive = false; } if ((reaction1 == null) && (reagents[0] != reagents[2])) { reactionKnown = false; } if ((reaction2 == null) && (reagents[1] != reagents[2])) { reactionKnown = false; } } } else { reactionKnown = false; ingredient3ComboBox.Sensitive = false; } expectedColor.Set(recipe.BaseColor); unmodifiedSwatch.Color = expectedColor; //SetExpectedColor(recipeColor.Red, recipeColor.Green, recipeColor.Blue); if (reactionKnown) { reactedColor.Set(recipe.ReactedColor); reactionSwatch.Color = reactedColor; } else { reactionSwatch.Clear(); } } unsafe bool CaptureReactionColor() { // Take a screenshot. int screenWidth, screenHeight; bool debugScreenshot = false; bool enableDebugMenu = false; Gdk.Window rootWindow = Gdk.Global.DefaultRootWindow; DesertPaintLab.AppSettings.Get("ScreenWidth", out screenWidth); DesertPaintLab.AppSettings.Get("ScreenHeight", out screenHeight); DesertPaintLab.AppSettings.Get("EnableDebugMenu", out enableDebugMenu); DesertPaintLab.AppSettings.Get("DebugScreenshot", out debugScreenshot); Gdk.Image rootImage = rootWindow.GetImage(0, 0, screenWidth, screenHeight); screenBuffer.GetFromImage(rootImage, rootImage.Colormap, 0, 0, 0, 0, screenWidth, screenHeight); rootImage.Unref(); System.GC.Collect(); // really, clean up now //screenBuffer.GetFromDrawable(rootWindow, // rootWindow.Colormap, 0, 0, 0, 0, screenWidth, screenHeight); int stride = screenBuffer.Rowstride; byte* pixBytes = (byte*)screenBuffer.Pixels; int redPixelStart = -1; StreamWriter log = null; if (enableDebugMenu) { string logfile = FileUtils.FindNumberedFile("DesertPaintLab_Capture", "log", Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)); log = new StreamWriter(logfile); ReactionRecorder.Instance.Log = log; } isCaptured = ReactionRecorder.Instance.CaptureReaction(pixBytes, screenWidth, screenHeight, stride, ref reactedColor, ref redPixelStart); if (log != null) { log.Flush(); log.Close(); log = null; } if (enableDebugMenu && debugScreenshot) { if (!isCaptured) { // write out the whole screenshot on a failure to capture string screenshotDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); string filename = FileUtils.FindNumberedFile("DesertPaintLab_Colormatch", "png", screenshotDir); screenBuffer.Save(filename, "png"); } else { // record the swatch that was captured // convert to pixel offset instead of byte int redPixelStartX = (redPixelStart % stride) / 3; int redPixelStartY = (redPixelStart / stride); // write out the screenshot string screenshotDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); string filename = FileUtils.FindNumberedFile("DesertPaintLab_Colormatch", "png", screenshotDir); int captureAreaWidth = Math.Min(64, screenWidth - redPixelStartX + 64); int captureAreaHeight = Math.Min(64, screenHeight - redPixelStartY + 64); Gdk.Pixbuf outPixBuf = new Gdk.Pixbuf(screenBuffer, Math.Max(0, redPixelStartX - 32), Math.Max(0, redPixelStartY - 32), captureAreaWidth, captureAreaHeight); //screenBuffer.Save(filename, "png"); outPixBuf.Save(filename, "png"); } } //screenBuffer.Save("screenshot.png", "png"); return isCaptured; } protected virtual void OnCapture(object sender, System.EventArgs e) { if (CaptureReactionColor()) { string warning = ""; if (reactedColor.Red == 0) { warning = warning + "\nRed is too low."; } if (reactedColor.Green == 0) { warning = warning + "\nGreen is too low."; } if (reactedColor.Blue == 0) { warning = warning + "\nBlue is too low."; } if (reactedColor.Red == 255) { warning = warning + "\nRed is too high."; } if (reactedColor.Green == 255) { warning = warning + "\nGreen is too high."; } if (reactedColor.Blue == 255) { warning = warning + "\nBlue is too high."; } if (warning.Length != 0) { isCaptured = true; Gtk.MessageDialog md = new Gtk.MessageDialog((Gtk.Window)Toplevel, Gtk.DialogFlags.DestroyWithParent, Gtk.MessageType.Error, Gtk.ButtonsType.Ok, "Reaction clipped. You will need to do a " + "3-way reaction to test this pair. Details: " + warning); md.Run(); md.Destroy(); } else { this.reactionSwatch.Color = reactedColor; recordButton.Sensitive = recordEnabled; } } else { Gtk.MessageDialog md = new Gtk.MessageDialog((Gtk.Window)Toplevel, Gtk.DialogFlags.DestroyWithParent, Gtk.MessageType.Error, Gtk.ButtonsType.Ok, "Pigment Lab dialog box NOT FOUND. Please ensure " + "that there is an unobstructed view of the dialog " + "and that your interface size is set to 'small' " + "when you press the Capture button."); md.Run(); md.Destroy(); } } protected virtual void OnRecord(object sender, System.EventArgs e) { if (ReactionRecorder.Instance.RecordReaction(profile, expectedColor, reactedColor, reagents)) { recordButton.Sensitive = false; } } protected virtual void OnChangedIngredient1(object sender, System.EventArgs e) { UpdateIngredients(); } protected virtual void OnChangedIngredient2(object sender, System.EventArgs e) { UpdateIngredients(); } protected virtual void OnChangedIngredient3(object sender, System.EventArgs e) { UpdateIngredients(); } protected void OnClearReaction(object sender, EventArgs e) { string reagentName1 = GetSelectedReagentName(1); string reagentName2 = GetSelectedReagentName(2); string reagentName3 = GetSelectedReagentName(3); if ((reagentName1 != null) && (reagentName2 != null) && (reagentName3 == null)) { Reagent reagent1 = ReagentManager.GetReagent(reagentName1); Reagent reagent2 = ReagentManager.GetReagent(reagentName2); if (null != profile.FindReaction(reagent1, reagent2)) { Gtk.MessageDialog md = new Gtk.MessageDialog((Gtk.Window)Toplevel, Gtk.DialogFlags.DestroyWithParent, Gtk.MessageType.Warning, Gtk.ButtonsType.OkCancel, "This will delete the reaction status between " + // TODO: ingredient1Name + " and " + ingredient2Name + "\n\n" + "ARE YOU SURE?" ); Gtk.ResponseType response = (Gtk.ResponseType)md.Run(); if (response == Gtk.ResponseType.Ok) { // really delete it profile.ClearReaction(reagent1, reagent2); } md.Destroy(); } } } } }