Changeset - 991c95f4da74
[Not reviewed]
default
0 6 0
Jason Maltzen - 9 years ago 2016-03-11 09:12:20
jason@hiddenachievement.com
Add some logging, fix a bug finding the paint dialog.
6 files changed with 176 insertions and 42 deletions:
0 comments (0 inline, 0 general)
DesertPaintLab.csproj
Show inline comments
 
<?xml version="1.0" encoding="utf-8"?>
 
<?xml version="1.0" encoding="utf-8"?>
 
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
 
  <PropertyGroup>
 
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
 
    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
 
    <ProjectGuid>{1A885212-5FD2-4EBF-A98F-3EB1491A1CBB}</ProjectGuid>
 
    <OutputType>WinExe</OutputType>
 
    <RootNamespace>DesertPaintLab</RootNamespace>
 
    <AssemblyName>DesertPaintLab</AssemblyName>
 
    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
 
    <PublishUrl>publish\</PublishUrl>
 
    <Install>true</Install>
 
    <InstallFrom>Disk</InstallFrom>
 
    <UpdateEnabled>false</UpdateEnabled>
 
    <UpdateMode>Foreground</UpdateMode>
 
    <UpdateInterval>7</UpdateInterval>
 
    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
 
    <UpdatePeriodically>false</UpdatePeriodically>
 
    <UpdateRequired>false</UpdateRequired>
 
    <MapFileExtensions>true</MapFileExtensions>
 
    <ApplicationRevision>0</ApplicationRevision>
 
    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
 
    <IsWebBootstrapper>false</IsWebBootstrapper>
 
    <UseApplicationTrust>false</UseApplicationTrust>
 
    <BootstrapperEnabled>true</BootstrapperEnabled>
 
  </PropertyGroup>
 
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
 
    <DebugSymbols>true</DebugSymbols>
 
    <DebugType>full</DebugType>
 
    <Optimize>false</Optimize>
 
    <OutputPath>bin\Debug</OutputPath>
 
    <DefineConstants>DEBUG</DefineConstants>
 
    <ErrorReport>prompt</ErrorReport>
 
    <WarningLevel>4</WarningLevel>
 
    <PlatformTarget>x86</PlatformTarget>
 
    <ConsolePause>false</ConsolePause>
 
    <additionalargs>/unsafe</additionalargs>
 
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
 
  </PropertyGroup>
 
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
 
    <DebugType>none</DebugType>
 
    <Optimize>false</Optimize>
 
    <OutputPath>bin\Release</OutputPath>
 
    <ErrorReport>prompt</ErrorReport>
 
    <WarningLevel>4</WarningLevel>
 
    <PlatformTarget>x86</PlatformTarget>
 
    <ConsolePause>false</ConsolePause>
 
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
 
  </PropertyGroup>
 
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
 
    <DebugSymbols>true</DebugSymbols>
 
    <OutputPath>bin\x64\Debug\</OutputPath>
 
    <DefineConstants>DEBUG</DefineConstants>
 
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
 
    <DebugType>full</DebugType>
 
    <PlatformTarget>x64</PlatformTarget>
 
    <ErrorReport>prompt</ErrorReport>
 
    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
 
    <Prefer32Bit>true</Prefer32Bit>
 
  </PropertyGroup>
 
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
 
    <OutputPath>bin\x64\Release\</OutputPath>
 
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
 
    <PlatformTarget>x64</PlatformTarget>
 
    <ErrorReport>prompt</ErrorReport>
 
    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
 
    <Prefer32Bit>true</Prefer32Bit>
 
  </PropertyGroup>
 
  <ItemGroup>
 
    <Reference Include="gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
 
    <Reference Include="gdk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
 
    <Reference Include="System" />
 
    <Reference Include="glib-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
 
    <Reference Include="glade-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
 
    <Reference Include="pango-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
 
    <Reference Include="atk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
 
    <Reference Include="System.IO.Compression.FileSystem" />
 
  </ItemGroup>
 
  <ItemGroup>
 
    <EmbeddedResource Include="gtk-gui\gui.stetic">
 
      <LogicalName>gui.stetic</LogicalName>
 
    </EmbeddedResource>
 
  </ItemGroup>
 
  <ItemGroup>
 
    <Compile Include="gtk-gui\generated.cs" />
 
    <Compile Include="MainWindow.cs" />
 
    <Compile Include="Main.cs" />
 
    <Compile Include="AssemblyInfo.cs" />
 
    <Compile Include="PlayerProfile.cs" />
 
    <Compile Include="FirstRunDialog.cs" />
 
    <Compile Include="SelectProfileDialog.cs" />
 
    <Compile Include="NewProfileDialog.cs" />
 
    <Compile Include="PaintSwatch.cs" />
 
    <Compile Include="Palette.cs" />
 
    <Compile Include="PaintColor.cs" />
 
    <Compile Include="Reaction.cs" />
 
    <Compile Include="ReagentManager.cs" />
 
    <Compile Include="Reagent.cs" />
 
    <Compile Include="gtk-gui\MainWindow.cs" />
 
    <Compile Include="gtk-gui\DesertPaintLab.FirstRunDialog.cs" />
 
    <Compile Include="gtk-gui\DesertPaintLab.SelectProfileDialog.cs" />
 
    <Compile Include="gtk-gui\DesertPaintLab.NewProfileDialog.cs" />
 
    <Compile Include="gtk-gui\DesertPaintLab.PaintSwatch.cs" />
 
    <Compile Include="ScreenCheckDialog.cs" />
 
    <Compile Include="gtk-gui\DesertPaintLab.ScreenCheckDialog.cs" />
 
    <Compile Include="FileUtils.cs" />
 
    <Compile Include="PaintRecipe.cs" />
 
    <Compile Include="ReactionRecorder.cs" />
 
    <Compile Include="ReactionStatusWindow.cs" />
 
    <Compile Include="gtk-gui\DesertPaintLab.ReactionStatusWindow.cs" />
 
    <Compile Include="ReactionSet.cs" />
 
    <Compile Include="RecipeGenerator.cs" />
 
    <Compile Include="ReagentWindow.cs" />
 
    <Compile Include="gtk-gui\DesertPaintLab.ReagentWindow.cs" />
 
    <Compile Include="RecipeSearchNode.cs" />
 
    <Compile Include="Settings.cs" />
 
    <Compile Include="gtk-gui\DesertPaintLab.CaptureView.cs" />
 
    <Compile Include="UI\CaptureView.cs" />
 
    <Compile Include="UI\RecipeGeneratorView.cs" />
 
    <Compile Include="gtk-gui\DesertPaintLab.RecipeGeneratorView.cs" />
 
    <Compile Include="UI\SimulatorView.cs" />
 
    <Compile Include="gtk-gui\DesertPaintLab.SimulatorView.cs" />
 
    <Compile Include="StatusUpdateEventArgs.cs" />
 
    <Compile Include="AppSettings.cs" />
 
  </ItemGroup>
 
  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
 
  <ProjectExtensions>
 
    <MonoDevelop>
 
      <Properties>
 
        <Policies>
 
          <TextStylePolicy inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp" />
 
          <CSharpFormattingPolicy IndentSwitchBody="True" IndentBlocksInsideExpressions="True" AnonymousMethodBraceStyle="NextLine" PropertyBraceStyle="NextLine" PropertyGetBraceStyle="NextLine" PropertySetBraceStyle="NextLine" EventBraceStyle="NextLine" EventAddBraceStyle="NextLine" EventRemoveBraceStyle="NextLine" StatementBraceStyle="NextLine" ElseNewLinePlacement="NewLine" CatchNewLinePlacement="NewLine" FinallyNewLinePlacement="NewLine" WhileNewLinePlacement="DoNotCare" ArrayInitializerWrapping="DoNotChange" ArrayInitializerBraceStyle="NextLine" BeforeMethodDeclarationParentheses="False" BeforeMethodCallParentheses="False" BeforeConstructorDeclarationParentheses="False" NewLineBeforeConstructorInitializerColon="NewLine" NewLineAfterConstructorInitializerColon="SameLine" BeforeDelegateDeclarationParentheses="False" NewParentheses="False" SpacesBeforeBrackets="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp" />
 
        </Policies>
 
        <GtkDesignInfo generateGettext="False" />
 
      </Properties>
 
    </MonoDevelop>
 
  </ProjectExtensions>
 
  <ItemGroup>
 
    <None Include="data\colors.txt">
 
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 
    </None>
 
    <None Include="data\ingredients.txt">
 
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 
    </None>
 
    <None Include="data\template\dp_reactions.txt">
 
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 
    </None>
 
    <None Include="data\template\ingredients.txt">
 
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 
    </None>
 
  </ItemGroup>
 
  <ItemGroup />
 
  <ItemGroup>
 
    <Folder Include="UI\" />
 
    <BootstrapperPackage Include=".NETFramework,Version=v4.5">
 
      <Visible>False</Visible>
 
      <ProductName>Microsoft .NET Framework 4.5 %28x86 and x64%29</ProductName>
 
      <Install>true</Install>
 
    </BootstrapperPackage>
 
    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
 
      <Visible>False</Visible>
 
      <ProductName>.NET Framework 3.5 SP1</ProductName>
 
      <Install>false</Install>
 
    </BootstrapperPackage>
 
  </ItemGroup>
 
</Project>
...
 
\ No newline at end of file
DesertPaintLab.sln
Show inline comments
 

 
Microsoft Visual Studio Solution File, Format Version 12.00
 
# Visual Studio 2012
 
# Visual Studio 14
 
VisualStudioVersion = 14.0.23107.0
 
MinimumVisualStudioVersion = 10.0.40219.1
 
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DesertPaintLab", "DesertPaintLab.csproj", "{1A885212-5FD2-4EBF-A98F-3EB1491A1CBB}"
 
EndProject
 
Global
 
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 
		Debug|x64 = Debug|x64
 
		Debug|x86 = Debug|x86
 
		Release|x64 = Release|x64
 
		Release|x86 = Release|x86
 
	EndGlobalSection
 
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
 
		{1A885212-5FD2-4EBF-A98F-3EB1491A1CBB}.Debug|x64.ActiveCfg = Debug|x64
 
		{1A885212-5FD2-4EBF-A98F-3EB1491A1CBB}.Debug|x64.Build.0 = Debug|x64
 
		{1A885212-5FD2-4EBF-A98F-3EB1491A1CBB}.Debug|x86.ActiveCfg = Debug|x86
 
		{1A885212-5FD2-4EBF-A98F-3EB1491A1CBB}.Debug|x86.Build.0 = Debug|x86
 
		{1A885212-5FD2-4EBF-A98F-3EB1491A1CBB}.Release|x64.ActiveCfg = Release|x64
 
		{1A885212-5FD2-4EBF-A98F-3EB1491A1CBB}.Release|x64.Build.0 = Release|x64
 
		{1A885212-5FD2-4EBF-A98F-3EB1491A1CBB}.Release|x86.ActiveCfg = Release|x86
 
		{1A885212-5FD2-4EBF-A98F-3EB1491A1CBB}.Release|x86.Build.0 = Release|x86
 
	EndGlobalSection
 
	GlobalSection(SolutionProperties) = preSolution
 
		HideSolutionNode = FALSE
 
	EndGlobalSection
 
EndGlobal
FileUtils.cs
Show inline comments
...
 
@@ -22,99 +22,111 @@ namespace DesertPaintLab
 
            string dirPath = System.IO.Path.Combine(
 
                    System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
 
                    dirname);
 
            if (System.IO.Directory.Exists(dirPath))
 
            {
 
                return dirPath;
 
            }
 
            dirPath = System.IO.Path.Combine(
 
                System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
 
                "data", 
 
                dirname);
 
            if (System.IO.Directory.Exists(dirPath))
 
            {
 
                return dirPath;
 
            }
 
            // try "Resources" in case this is a Mac app bundle
 
            dirPath = System.IO.Path.Combine(
 
                Environment.GetFolderPath(Environment.SpecialFolder.Resources), "data", dirname);
 
            if (System.IO.Directory.Exists(dirPath))
 
            {
 
                return dirPath;
 
            }
 
            // try "Resources" in case this is a Mac app bundle
 
            dirPath = System.IO.Path.Combine(
 
                Environment.GetFolderPath(Environment.SpecialFolder.Resources), dirname);
 
            if (System.IO.Directory.Exists(dirPath))
 
            {
 
                return dirPath;
 
            }
 
            dirPath = System.IO.Path.Combine(
 
                System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
 
                "Resources", "data",
 
                dirname);
 
            if (System.IO.Directory.Exists(dirPath))
 
            {
 
                // not found
 
                return dirPath;
 
            }
 
            dirPath = System.IO.Path.Combine(
 
                System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
 
                "Resources", 
 
                dirname);
 
            if (!System.IO.Directory.Exists(dirPath))
 
            {
 
                // not found
 
                dirPath = null;
 
            }
 
            return dirPath;
 
        }
 

	
 
        public static string FindApplicationResourceFile(string filename)
 
        {
 
            // start with the location of the executable
 
            string filePath = System.IO.Path.Combine(
 
                    System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
 
                    filename);
 
            if (!System.IO.File.Exists(filePath))
 
            {
 
                filePath = System.IO.Path.Combine(
 
                    System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
 
                    "data", 
 
                    filename);
 
            }
 
            if (!System.IO.File.Exists(filePath))
 
            {
 
                // try "Resources/data" in case this is a Mac app bundle
 
                filePath = System.IO.Path.Combine(
 
                    Environment.GetFolderPath(Environment.SpecialFolder.Resources), "data", filename);
 
            }
 
            if (!System.IO.File.Exists(filePath))
 
            {
 
                // try "Resources" in case this is a Mac app bundle
 
                filePath = System.IO.Path.Combine(
 
                    Environment.GetFolderPath(Environment.SpecialFolder.Resources), filename);
 
            }
 
            if (!System.IO.File.Exists(filePath))
 
            {
 
                filePath = System.IO.Path.Combine(
 
                    System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
 
                    "Resources", "data",
 
                    filename);
 
            }
 
            if (!System.IO.File.Exists(filePath))
 
            {
 
                filePath = System.IO.Path.Combine(
 
                    System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
 
                    "Resources", 
 
                    filename);
 
            }
 
            if (!System.IO.File.Exists(filePath))
 
            {
 
                // not found
 
                filePath = null;
 
            }
 
            return filePath;
 
        }
 

	
 
        public static string FindNumberedFile(string baseName, string extension, string folder)
 
        {
 
            string filename = "";
 
            int i = 0;
 
            do
 
            {
 
                ++i;
 
                filename = System.IO.Path.Combine(folder, String.Format("{0}_{1}.{2}", baseName, i, extension));
 
            } while (System.IO.File.Exists(filename));
 
            return filename;
 
        }
 
    }
 
}
 

	
MainWindow.cs
Show inline comments
...
 
@@ -46,193 +46,193 @@ public partial class MainWindow : Gtk.Wi
 

	
 
	public bool ShouldShutDown
 
	{
 
		get
 
		{
 
			return shouldShutDown;
 
		}
 
	}
 
	
 
	public MainWindow () : base(Gtk.WindowType.Toplevel)
 
	{
 
        string appDataPath = FileUtils.AppDataPath;
 
		if (!System.IO.Directory.Exists(appDataPath))
 
		{
 
			System.IO.Directory.CreateDirectory(appDataPath);	
 
		}
 
		
 
		DirectoryInfo di = new DirectoryInfo(appDataPath);
 
		DirectoryInfo[] dirs = di.GetDirectories();
 
		foreach (DirectoryInfo dir in dirs)
 
		{
 
			if (dir.Name != "template")
 
			{
 
				profileList.Add(dir.Name);
 
			}
 
		}
 

	
 
        string colorsPath = FileUtils.FindApplicationResourceFile("colors.txt");
 
        if (colorsPath == null)
 
        {
 
            // failed to find colors.txt file
 
            MessageDialog md = new MessageDialog(this, 
 
                DialogFlags.DestroyWithParent,
 
                MessageType.Error, ButtonsType.Close, 
 
                "Failed to find colors.txt file. Please check your installation.");
 
       
 
            md.Run();
 
            md.Destroy();
 
            Application.Quit();
 
        }
 
		Palette.Load(colorsPath);
 

	
 
        string ingredientsPath = FileUtils.FindApplicationResourceFile("ingredients.txt");
 
        if (ingredientsPath == null)
 
        {
 
            // failed to find ingredients.txt file
 
            MessageDialog md = new MessageDialog(this, 
 
                DialogFlags.DestroyWithParent,
 
                MessageType.Error, ButtonsType.Close, 
 
                "Failed to find ingredients.txt file. Please check your installation.");
 
       
 
            md.Run();
 
            md.Destroy();
 
            Application.Quit();
 
        }
 
        ReagentManager.Load(ingredientsPath);
 
		
 
		Build();
 
		
 
		// get the root window
 
		rootWindow = Gdk.Global.DefaultRootWindow;
 

	
 
		// get its width and height
 
        int screenWidth;
 
        int screenHeight;
 
		rootWindow.GetSize(out screenWidth, out screenHeight);
 
        int pixelMultiplier = 1;
 

	
 
        if ( DesertPaintLab.AppSettings.Load() == true )
 
        {
 
            DesertPaintLab.AppSettings.Get("ScreenWidth", out screenWidth);
 
            DesertPaintLab.AppSettings.Get("ScreenHeight", out screenHeight);
 
            DesertPaintLab.AppSettings.Get("PixelMultiplier", out pixelMultiplier);
 
        }
 

	
 
        bool enableDebugMenu;
 
        DesertPaintLab.AppSettings.Get("EnableDebugMenu", out enableDebugMenu);
 
        this.DebugAction.Visible = enableDebugMenu;
 

	
 
		ScreenCheckDialog screenCheckDialog = new ScreenCheckDialog();
 
		screenCheckDialog.ScreenWidth = screenWidth;
 
		screenCheckDialog.ScreenHeight = screenHeight;
 
        screenCheckDialog.GamePixelWidth = pixelMultiplier;
 
		ResponseType resp = (ResponseType)screenCheckDialog.Run();
 
        screenWidth = screenCheckDialog.ScreenWidth;
 
        screenHeight = screenCheckDialog.ScreenHeight;
 
        pixelMultiplier = screenCheckDialog.GamePixelWidth;
 
		screenCheckDialog.Destroy();
 

	
 
        DesertPaintLab.AppSettings.Set("ScreenWidth", screenWidth);
 
        DesertPaintLab.AppSettings.Set("ScreenHeight", screenHeight);
 
        DesertPaintLab.AppSettings.Set("PixelMultiplier", pixelMultiplier);
 
        DesertPaintLab.AppSettings.Save();
 

	
 
		screenBuffer = new Gdk.Pixbuf(Gdk.Colorspace.Rgb, false, 8, screenWidth, screenHeight);
 
	
 
        ReactionRecorder.SetPixelMultiplier(pixelMultiplier);
 
        ReactionRecorder.Instance.SetPixelMultiplier(pixelMultiplier);
 

	
 
		if (!OpenProfile())
 
		{
 
			shouldShutDown = true;
 
		}
 

	
 
        captureView = new CaptureView(profile, screenBuffer);
 
        generatorView = new RecipeGeneratorView(profile);
 
        generatorView.SetStatus += OnStatusUpdate;
 
        generatorView.Started += OnGeneratorRunning;
 
        generatorView.Stopped += OnGeneratorStopped;
 
        simulatorView = new SimulatorView(profile);
 

	
 
        contentContainer.Add(captureView);
 
        captureView.Show();
 
	}
 

	
 
	bool ConfirmedExit()
 
	{
 
		if (unsavedData)
 
		{
 
			MessageDialog md = new MessageDialog(this, 
 
	            DialogFlags.DestroyWithParent,
 
	            MessageType.Warning, ButtonsType.OkCancel, 
 
	            "Your last reaction was unsaved." +
 
	            "Are you sure you want to quit?");
 
	   
 
			ResponseType resp = (ResponseType)md.Run();
 
			md.Destroy();
 
			return (resp == ResponseType.Ok);
 
		}
 
		return true;
 
	}
 

	
 
    protected void OnStatusUpdate(object sender, EventArgs args)
 
    {
 
        StatusUpdateEventArgs statusArgs = (StatusUpdateEventArgs)args;
 
        statusBar.Push(0, statusArgs.Status);
 
    }
 

	
 
    protected void OnGeneratorRunning(object sender, EventArgs args)
 
    {
 
        NewProfileAction.Sensitive = false;
 
        OpenProfileAction.Sensitive = false;
 
        ImportProfileAction.Sensitive = false;
 
        if (captureView != null)
 
        {
 
            captureView.DisableRecord();
 
        }
 
    }
 

	
 
    protected void OnGeneratorStopped(object sender, EventArgs args)
 
    {
 
        NewProfileAction.Sensitive = true;
 
        OpenProfileAction.Sensitive = true;
 
        ImportProfileAction.Sensitive = true;
 
        if (captureView != null)
 
        {
 
            captureView.EnableRecord();
 
        }
 
    }
 
	
 
	void SetProfileName(string name)
 
	{	
 
		profile = new PlayerProfile(name,
 
            System.IO.Path.Combine(FileUtils.AppDataPath, name));
 
	}
 

	
 
    void ProfileChanged()
 
    {
 
        statusBar.Push(0, "Profile: " + profile.Name);
 
        Title  = "Desert Paint Lab - " + profile.Name;
 

	
 
        if (generatorView != null)
 
        {
 
            generatorView.Profile = profile;
 
        }
 
        if (simulatorView != null)
 
        {
 
            simulatorView.Profile = profile;
 
        }
 
        if (captureView != null)
 
        {
 
            captureView.Profile = profile;
 
        }
 
    }
 
	
 
	bool NewProfile()
 
	{
 
		bool newProfileCreated = false;
 
		bool duplicateName = false;
 
		NewProfileDialog newProfileDialog = new NewProfileDialog();
 
		ResponseType resp = (ResponseType)newProfileDialog.Run();
 
		if (resp == ResponseType.Ok)
 
		{
 
			// Make sure profile doesn't already exist.
ReactionRecorder.cs
Show inline comments
 
/*
 
 * Copyright (c) 2015, Jason Maltzen
 

	
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 
 of this software and associated documentation files (the "Software"), to deal
 
 in the Software without restriction, including without limitation the rights
 
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 
 copies of the Software, and to permit persons to whom the Software is
 
 furnished to do so, subject to the following conditions:
 

	
 
 The above copyright notice and this permission notice shall be included in
 
 all copies or substantial portions of the Software.
 

	
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 
 THE SOFTWARE.
 
*/
 

	
 
using System;
 
using System.IO;
 

	
 
namespace DesertPaintLab
 
{
 
    // ReactionRecorder - business logic for recording paint reactions
 
    public class ReactionRecorder
 
    {
 
        const int COLOR_TOLERANCE = 3;
 

	
 
        const int DEFAULT_SWATCH_HEIGHT = 24; // including top and bottom borders
 
        const int DEFAULT_SWATCH_WIDTH = 260;
 
        const int DEFAULT_COLOR_BAR_WIDTH = 306;
 
        const int DEFAULT_RED_BAR_SPACING = 32;
 
        const int DEFAULT_GREEN_BAR_SPACING = 42;
 
        const int DEFAULT_BLUE_BAR_SPACING = 52;
 

	
 
        const int DEFAULT_SWATCH_TEST_WIDTH = 26; // width to test on ends of swatch (10% on either end)
 

	
 
        static int swatchHeight = DEFAULT_SWATCH_HEIGHT;
 
        static int swatchWidth = DEFAULT_SWATCH_WIDTH;
 
        static int swatchTestWidth = DEFAULT_SWATCH_TEST_WIDTH;
 
        static int colorBarWidth = DEFAULT_COLOR_BAR_WIDTH;
 
        static int redBarSpacing = DEFAULT_RED_BAR_SPACING;
 
        static int greenBarSpacing = DEFAULT_GREEN_BAR_SPACING;
 
        static int blueBarSpacing = DEFAULT_BLUE_BAR_SPACING;
 
        static int pixelMultiplier = 1;
 
        int swatchHeight = DEFAULT_SWATCH_HEIGHT;
 
        int swatchWidth = DEFAULT_SWATCH_WIDTH;
 
        int swatchTestWidth = DEFAULT_SWATCH_TEST_WIDTH;
 
        int colorBarWidth = DEFAULT_COLOR_BAR_WIDTH;
 
        int redBarSpacing = DEFAULT_RED_BAR_SPACING;
 
        int greenBarSpacing = DEFAULT_GREEN_BAR_SPACING;
 
        int blueBarSpacing = DEFAULT_BLUE_BAR_SPACING;
 
        int pixelMultiplier = 1;
 

	
 
        private static ReactionRecorder _instance;
 
        public static ReactionRecorder Instance
 
        {
 
            get {
 
                if (_instance == null)
 
                {
 
                    _instance = new ReactionRecorder();
 
                }
 
                return _instance;
 
            }
 
        }
 

	
 
        private StreamWriter _log;
 
        public StreamWriter Log
 
        {
 
            set
 
            {
 
                _log = value;
 
            }
 
        }
 
        private void WriteLog(string format, params object[] args)
 
        {
 
            if (_log != null)
 
            {
 
                _log.WriteLine(format, args);
 
            }
 
        }
 

	
 
        public ReactionRecorder()
 
        {
 
            this.pixelMultiplier = 1;
 
            swatchHeight = DEFAULT_SWATCH_HEIGHT * pixelMultiplier;
 
            swatchWidth = DEFAULT_SWATCH_WIDTH * pixelMultiplier;
 
            colorBarWidth = DEFAULT_COLOR_BAR_WIDTH * pixelMultiplier;
 
            redBarSpacing = DEFAULT_RED_BAR_SPACING * pixelMultiplier;
 
            greenBarSpacing = DEFAULT_GREEN_BAR_SPACING * pixelMultiplier;
 
            blueBarSpacing = DEFAULT_BLUE_BAR_SPACING * pixelMultiplier;
 
            swatchTestWidth = DEFAULT_SWATCH_TEST_WIDTH * pixelMultiplier;
 
        }
 

	
 
        public ReactionRecorder(int pixelMultiplier)
 
        {
 
            this.pixelMultiplier = pixelMultiplier;
 
            swatchHeight = DEFAULT_SWATCH_HEIGHT * pixelMultiplier;
 
            swatchWidth = DEFAULT_SWATCH_WIDTH * pixelMultiplier;
 
            colorBarWidth = DEFAULT_COLOR_BAR_WIDTH * pixelMultiplier;
 
            redBarSpacing = DEFAULT_RED_BAR_SPACING * pixelMultiplier;
 
            greenBarSpacing = DEFAULT_GREEN_BAR_SPACING * pixelMultiplier;
 
            blueBarSpacing = DEFAULT_BLUE_BAR_SPACING * pixelMultiplier;
 
            swatchTestWidth = DEFAULT_SWATCH_TEST_WIDTH * pixelMultiplier;
 
        }
 

	
 
        private static bool IsPapyTexture(byte r, byte g, byte b)
 
        {
 
            // red between 208 and 244
 
            // green between 192 and 237
 
            // blue between 145 and 205
 
            return ((r > 0xD0) && (g >= 0xC0) && (b >= 0x91)) &&
 
                   ((r < 0xF4) && (g <= 0xED) && (b <= 0xCD));
 
        }
 

	
 
        public static void SetPixelMultiplier(int pixelMultiplier)
 
        public void SetPixelMultiplier(int pixelMultiplier)
 
        {
 
            swatchHeight    = DEFAULT_SWATCH_HEIGHT * pixelMultiplier;
 
            swatchWidth     = DEFAULT_SWATCH_WIDTH * pixelMultiplier;
 
            colorBarWidth   = DEFAULT_COLOR_BAR_WIDTH * pixelMultiplier;
 
            redBarSpacing   = DEFAULT_RED_BAR_SPACING * pixelMultiplier;
 
            greenBarSpacing = DEFAULT_GREEN_BAR_SPACING * pixelMultiplier;
 
            blueBarSpacing  = DEFAULT_BLUE_BAR_SPACING * pixelMultiplier;
 
            swatchTestWidth = DEFAULT_SWATCH_TEST_WIDTH * pixelMultiplier;
 
            ReactionRecorder.pixelMultiplier = pixelMultiplier;
 
            this.pixelMultiplier = pixelMultiplier;
 
        }
 

	
 
        unsafe private static void ColorAt(byte *pixBytes, int x, int y, int stride, out byte r, out byte g, out byte b)
 
        unsafe private void ColorAt(byte *pixBytes, int x, int y, int stride, out byte r, out byte g, out byte b)
 
        {
 
            int pixelStart = (y * stride) + (x * 3);
 
                    r = pixBytes[pixelStart];
 
                    g = pixBytes[pixelStart + 1];
 
                    b = pixBytes[pixelStart + 2];
 
        }
 

	
 
        private static bool IsDarkPixel(int r, int g, int b)
 
        private bool IsDarkPixel(int r, int g, int b)
 
        {
 
            return ((r < 0x46) && (g < 0x46) && (b < 0x47));
 
        }
 

	
 
        private static bool IsColorMatch(byte test_r, byte test_g, byte test_b, byte target_r, byte target_g, byte target_b)
 
        private bool IsColorMatch(byte test_r, byte test_g, byte test_b, byte target_r, byte target_g, byte target_b)
 
        {
 
            return ((Math.Abs(test_r - target_r) <= COLOR_TOLERANCE) &&
 
                (Math.Abs(test_g - target_g) <= COLOR_TOLERANCE) &&
 
                (Math.Abs(test_b - target_b) <= COLOR_TOLERANCE));
 
        }
 

	
 
        unsafe private static bool IsPossibleSwatchSlice(byte* pixBytes, int x, int y, int stride)
 
        unsafe private bool IsPossibleSwatchSlice(byte* pixBytes, int x, int y, int stride)
 
        {
 
            int testPixelStart = (y * stride) + (x * 3);
 
            byte r = pixBytes[testPixelStart];
 
            byte g = pixBytes[testPixelStart+1];
 
            byte b = pixBytes[testPixelStart+2];
 

	
 
            bool isDarkPixel = false;
 
            //bool isPapyAbove = false;
 
            //bool isPapyBelow = false;
 

	
 
            // 1.) Check if the top pixel is a dark pixel.
 
            isDarkPixel = IsDarkPixel(r, g, b); // ((r < 0x46) && (g < 0x46) && (b < 0x46));
 
            
 
            //// 2.) Check the pixel above it to see if it's from the papy texture.
 
            //int otherPixelStart = testPixelStart - stride;
 
            //isPapyAbove = ((otherPixelStart >= 0) &&
 
            //    IsPapyTexture(pixBytes[otherPixelStart++], pixBytes[otherPixelStart++], pixBytes[otherPixelStart]));
 

	
 
            //// 3.) Check the pixel below where the swatch should be to see if it's also from the papy texture.
 
            //otherPixelStart = testPixelStart + (stride * swatchHeight);
 
            //isPapyBelow = (IsPapyTexture(pixBytes[otherPixelStart++], pixBytes[otherPixelStart++], pixBytes[otherPixelStart]));
 

	
 
            //bool result = isDarkPixel && isPapyAbove && isPapyBelow;
 
            bool result = isDarkPixel;
 

	
 
            // grab the swatch color
 
            int swatchColorStart = testPixelStart + (2 * pixelMultiplier * stride); // 2 rows below the test pixel, skipping the faded color
 
            r = pixBytes[swatchColorStart];
 
            g = pixBytes[swatchColorStart+1];
 
            b = pixBytes[swatchColorStart+2];
 

	
 
            // scan the column from 2 below the top to 2 above the bottom to ensure the color matches
 
            for (int i = (2*pixelMultiplier); result && (i < swatchHeight-(2*pixelMultiplier)); ++i)
 
            {
 
                int otherPixelStart = testPixelStart + (stride * i);
 
                result &= IsColorMatch(pixBytes[otherPixelStart], pixBytes[otherPixelStart+1], pixBytes[otherPixelStart+2], r, g, b);
 
            }
 

	
 
            if (!result)
 
            {
 
                WriteLog("Swatch slice at {0}, {1} failed to match", x, y);
 
            }
 

	
 
            return result;
 
        }
 

	
 
        unsafe private static bool IsPossibleSwatchUpperLeft(byte* pixBytes, int x, int y, int stride)
 
        unsafe private bool IsPossibleSwatchUpperLeft(byte* pixBytes, int x, int y, int stride)
 
        {
 
            int testPixelStart = (y * stride) + (x * 3);
 

	
 
            bool result = true;
 
            // test the left edge for dark pixels
 
            for (int i = 0; result && (i < swatchHeight-pixelMultiplier); ++i)
 
            int i = 0;
 
            for (i = 0; result && (i < swatchHeight-pixelMultiplier); ++i)
 
            {
 
                int otherPixelStart = testPixelStart + (stride * i);
 
                result &= IsDarkPixel(pixBytes[otherPixelStart], pixBytes[otherPixelStart+1], pixBytes[otherPixelStart+2]);
 
            }
 

	
 
            // test the dark top border and for papyrus above and below the swatch
 
            int papyErrorCount = 0;
 
            for (int i = 0; result && (i < swatchWidth); ++i)
 
            for (i = 0; result && (i < swatchWidth); ++i)
 
            {
 
                int otherPixelStart = testPixelStart + (3 * i);
 
                result &= IsDarkPixel(pixBytes[otherPixelStart], pixBytes[otherPixelStart+1], pixBytes[otherPixelStart+2]);
 
                otherPixelStart = otherPixelStart - stride;
 
                papyErrorCount += (IsPapyTexture(pixBytes[otherPixelStart], pixBytes[otherPixelStart+1], pixBytes[otherPixelStart+2]) ? 1 : 0);
 
                papyErrorCount += (IsPapyTexture(pixBytes[otherPixelStart], pixBytes[otherPixelStart+1], pixBytes[otherPixelStart+2]) ? 0 : 1);
 
                otherPixelStart = testPixelStart + (stride * swatchHeight) + (3 * i);
 
                papyErrorCount += (IsPapyTexture(pixBytes[otherPixelStart], pixBytes[otherPixelStart+1], pixBytes[otherPixelStart+2]) ? 1 : 0);
 
                papyErrorCount += (IsPapyTexture(pixBytes[otherPixelStart], pixBytes[otherPixelStart+1], pixBytes[otherPixelStart+2]) ? 0 : 1);
 
            }
 

	
 
                result &= (papyErrorCount < (swatchWidth / 20)); // allow up to 5% error rate checking for papy texture, because this seems to be inconsistent
 
            if (!result && ((i > (swatchWidth*0.8)) || (papyErrorCount >= (swatchWidth/20))))
 
            {
 
                WriteLog("Found a potential swatch candidate of width {0} at {1},{2} that had {3} failures matching papyrus texture", i, x, y, papyErrorCount);
 
            }
 

	
 
            return result;
 
        }
 

	
 
        unsafe public static bool CaptureReaction(byte* pixBytes, int screenshotWidth, int screenshotHeight, int stride, ref PaintColor reactedColor, ref int redPixelStart)
 
        unsafe public bool CaptureReaction(byte* pixBytes, int screenshotWidth, int screenshotHeight, int stride, ref PaintColor reactedColor, ref int redPixelStart)
 
        {
 
            byte pixel_r, pixel_g, pixel_b;
 
            int pixelStart, otherPixelStart;
 
            bool colorMatch = true;
 
            for (int x = 0; x < screenshotWidth - colorBarWidth; ++x)
 
            {
 
                for (int y = 0; y < (screenshotHeight - (blueBarSpacing + 1)  /*53*/); ++y)
 
                {
 
                    // Look for the color swatch.
 
                    pixelStart = (y * stride) + (x * 3);
 
                    pixel_r = pixBytes[pixelStart];
 
                    pixel_g = pixBytes[pixelStart + 1];
 
                    pixel_b = pixBytes[pixelStart + 2];
 
                    
 
                    bool foundSwatch = IsPossibleSwatchUpperLeft(pixBytes, x, y, stride); // ((pixel_r < 0x46) && (pixel_g < 0x46) && (pixel_b < 0x46));
 
                    if (foundSwatch)
 
                    {
 
                        int borderXOffset = 0;
 
                        for (borderXOffset = (2 * pixelMultiplier); foundSwatch && (borderXOffset < swatchTestWidth); ++borderXOffset)
 
                        {
 
                            foundSwatch &= IsPossibleSwatchSlice(pixBytes, x + borderXOffset, y, stride);
 
                            foundSwatch &= IsPossibleSwatchSlice(pixBytes, x + swatchWidth - borderXOffset, y, stride);
 
                        }
 
                    }
 

	
 
                    if (foundSwatch)
 
                    {
 
                        // found a swatch with an appropriate dark top border with papyrus texture above it and papyrus a jump below it
 
                        // 4.) Scan the left border of the potential swatch
 
                        // location.
 
                        colorMatch = true;
 
                        for (int i = 2; i < swatchHeight - (2 * pixelMultiplier); ++i)
 
                        {
 
                            otherPixelStart = pixelStart + (stride * i);
 
                            if (!IsColorMatch(pixel_r, pixel_g, pixel_b, pixBytes[otherPixelStart], pixBytes[otherPixelStart+1], pixBytes[otherPixelStart+2]))
 
                            {
 
                                colorMatch = false;
 
                                break;
 
                            }
 
                        }
 
                        
 
                        if (colorMatch)
 
                        {
 
                            // WE FOUND THE SWATCH!
 
                            // Now we know where the color bars are.
 
                            redPixelStart = pixelStart + (redBarSpacing * stride);
 
                            int redPixelCount = 0;
 
                            while ((pixBytes[redPixelStart] > 0x9F) &&
 
                                   (pixBytes[redPixelStart + 1] < 0x62) &&
 
                                   (pixBytes[redPixelStart + 2]  < 0x62))
 
                            {
 
                                redPixelCount++;
 
                                // pixBytes[redPixelStart] = 0x00;
 
                                // pixBytes[redPixelStart + 1] = 0xFF;
 
                                // pixBytes[redPixelStart + 2] = 0xFF;
 
                                redPixelStart += 3;
 
                            }
 
                                
 
                            reactedColor.Red = (byte)Math.Round((float)redPixelCount * 255f / (float)colorBarWidth);
 
                            int greenPixelStart = pixelStart + (greenBarSpacing * stride);
 
                            
 
                            int greenPixelCount = 0;
 
                            while ((pixBytes[greenPixelStart] < 0x62) &&
 
                                   (pixBytes[greenPixelStart + 1] > 0x9F) &&
 
                                   (pixBytes[greenPixelStart + 2] < 0x62))
 
                            {
 
                                greenPixelCount++;
 
                                // pixBytes[greenPixelStart] = 0x00;
 
                                // pixBytes[greenPixelStart + 1] = 0xFF;
 
                                // pixBytes[greenPixelStart + 2] = 0xFF;
 
                                greenPixelStart += 3;
 
                            }
 

	
 
                            reactedColor.Green = (byte)Math.Round((float)greenPixelCount * 255f / (float)colorBarWidth);
 
                            int bluePixelStart = pixelStart + (blueBarSpacing * stride);
 
                            
 
                            int bluePixelCount = 0;
 
                            while ((pixBytes[bluePixelStart] < 0x62) &&
 
                                (pixBytes[bluePixelStart + 1] < 0x62) &&
 
                                (pixBytes[bluePixelStart + 2] > 0x9F))
 
                            {
 
                                bluePixelCount++;
 
                                // pixBytes[bluePixelStart] = 0x00;
 
                                // pixBytes[bluePixelStart + 1] = 0xFF;
 
                                // pixBytes[bluePixelStart + 2] = 0xFF;
 
                                bluePixelStart += 3;
 
                            }
 

	
 
                            reactedColor.Blue = (byte)Math.Round((float)bluePixelCount * 255f / (float)colorBarWidth);
 
                            WriteLog("Found the color swatch at {0}, {1}. Color={2}", x, y, reactedColor);
 
                            return true;
 
                        }
 
                    }
 
                }
 
            }
 
            return false;
 
        }
 

	
 
        public static bool RecordReaction(PlayerProfile profile, PaintColor expectedColor, PaintColor reactedColor, Reagent[] reagents)
 
        public bool RecordReaction(PlayerProfile profile, PaintColor expectedColor, PaintColor reactedColor, Reagent[] reagents)
 
        {
 
            bool saved = false;
 
            int r, g, b;
 
            if (reagents[2] != null)
 
            {
 
                // A 3-reagent reaction.
 
                Reaction reaction1 = profile.FindReaction(reagents[0], reagents[1]);
 
                Reaction reaction2 = profile.FindReaction(reagents[0], reagents[2]);
 
                Reaction reaction3 = profile.FindReaction(reagents[1], reagents[2]);
 
                
 
                r = reactedColor.Red - expectedColor.Red;
 
                g = reactedColor.Green - expectedColor.Green;
 
                b = reactedColor.Blue - expectedColor.Blue;
 
                
 
                if (reaction2 == null)
 
                {
 
                    r = r - reaction1.Red - reaction3.Red;
 
                    g = g - reaction1.Green - reaction3.Green;
 
                    b = b - reaction1.Blue - reaction3.Blue;
 
                    profile.SetReaction(reagents[0], reagents[2], new Reaction(r, g, b));
 
                    profile.Save();
 
                    saved = true;
 
                }
 
                else if (reaction3 == null)
 
                {
 
                    r = r - reaction1.Red - reaction2.Red;
 
                    g = g - reaction1.Green - reaction2.Green;
 
                    b = b - reaction1.Blue - reaction2.Blue;
 
                    profile.SetReaction(reagents[1], reagents[2], new Reaction(r, g, b));
 
                    profile.Save();
 
                    saved = true;
 
                }   
 
            }
 
            else if ((reagents[0] != null) && (reagents[1] != null))
 
            {
 
                // A 2-reagent reaction.
 
                r = reactedColor.Red - expectedColor.Red;
 
                g = reactedColor.Green - expectedColor.Green;
 
                b = reactedColor.Blue - expectedColor.Blue;
 
                profile.SetReaction(reagents[0], reagents[1], new Reaction(r, g, b));
 
                profile.Save();
 
                saved = true;
 
            }
 
            return saved;
 
        }
 
    }
 
}
 

	
UI/CaptureView.cs
Show inline comments
 
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;
 
        }
...
 
@@ -169,261 +170,262 @@ namespace DesertPaintLab
 
            // 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);
 
            //screenBuffer.GetFromDrawable(rootWindow,
 
            //  rootWindow.Colormap, 0, 0, 0, 0, screenWidth, screenHeight);
 
            int stride = screenBuffer.Rowstride;
 
            byte* pixBytes = (byte*)screenBuffer.Pixels;
 
            int redPixelStart = -1;
 
        
 
            isCaptured = ReactionRecorder.CaptureReaction(pixBytes, screenWidth, screenHeight, stride, ref reactedColor, ref redPixelStart);
 
            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;
 
                    int i = 0;
 
                    do
 
                    {
 
                        ++i;
 
                        filename = System.IO.Path.Combine(screenshotDir, String.Format("DesertPaintLab_Colormatch{0}.png", i));
 
                    } while (System.IO.File.Exists(filename));
 
                    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;
 
                    int i = 0;
 
                    do
 
                    {
 
                        ++i;
 
                        filename = System.IO.Path.Combine(screenshotDir, String.Format("DesertPaintLab_Colormatch{0}.png", i));
 
                    } while (System.IO.File.Exists(filename));
 
                    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 - 16), Math.Max(0, redPixelStartY - 16), captureAreaWidth, captureAreaHeight);
 
                    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.RecordReaction(profile, expectedColor, reactedColor, reagents))
 
            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();
 
                }
 
            }
 
        }
 
    }
 
}
 

	
0 comments (0 inline, 0 general)