Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial commit.

  • Loading branch information...
commit 2dd51fa614c90586df1b345e4eddfa4cea8f2541 0 parents
@jpobst jpobst authored
Showing with 9,570 additions and 0 deletions.
  1. +4 −0 .gitignore
  2. +3 −0  Pinta.Core/.gitignore
  3. +115 −0 Pinta.Core/Actions/AdjustmentsActions.cs
  4. +149 −0 Pinta.Core/Actions/EditActions.cs
  5. +168 −0 Pinta.Core/Actions/FileActions.cs
  6. +65 −0 Pinta.Core/Actions/HelpActions.cs
  7. +134 −0 Pinta.Core/Actions/ImageActions.cs
  8. +224 −0 Pinta.Core/Actions/LayerActions.cs
  9. +148 −0 Pinta.Core/Actions/ViewActions.cs
  10. +26 −0 Pinta.Core/AssemblyInfo.cs
  11. +139 −0 Pinta.Core/Classes/BaseTool.cs
  12. +200 −0 Pinta.Core/Classes/Layer.cs
  13. +1,808 −0 Pinta.Core/Effects/ColorBgra.cs
  14. +191 −0 Pinta.Core/Effects/HsvColor.cs
  15. +126 −0 Pinta.Core/Effects/PixelOp.cs
  16. +134 −0 Pinta.Core/Effects/RgbColor.cs
  17. +150 −0 Pinta.Core/Effects/UnaryPixelOp.cs
  18. +882 −0 Pinta.Core/Effects/UnaryPixelOps.cs
  19. +92 −0 Pinta.Core/Effects/Utility.cs
  20. +342 −0 Pinta.Core/Extensions/CairoExtensions.cs
  21. +45 −0 Pinta.Core/Extensions/GdkExtensions.cs
  22. +73 −0 Pinta.Core/Extensions/GtkExtensions.cs
  23. +45 −0 Pinta.Core/Extensions/ToolBarButton.cs
  24. +51 −0 Pinta.Core/Extensions/ToolBarComboBox.cs
  25. +43 −0 Pinta.Core/Extensions/ToolBarImage.cs
  26. +43 −0 Pinta.Core/Extensions/ToolBarLabel.cs
  27. +113 −0 Pinta.Core/Managers/ActionManager.cs
  28. +57 −0 Pinta.Core/Managers/ChromeManager.cs
  29. +458 −0 Pinta.Core/Managers/LayerManager.cs
  30. +43 −0 Pinta.Core/Managers/PaletteManager.cs
  31. +124 −0 Pinta.Core/Managers/ToolManager.cs
  32. +100 −0 Pinta.Core/Managers/ViewportManager.cs
  33. +85 −0 Pinta.Core/Pinta.Core.csproj
  34. +62 −0 Pinta.Core/PintaCore.cs
  35. +2 −0  Pinta.Resources/.gitignore
  36. +26 −0 Pinta.Resources/AssemblyInfo.cs
  37. +261 −0 Pinta.Resources/Pinta.Resources.csproj
  38. +43 −0 Pinta.Resources/ResourceManager.cs
  39. BIN  Pinta.Resources/Resources/ColorPalette.SwapIcon.png
  40. BIN  Pinta.Resources/Resources/LayersWidget.Hidden.png
  41. BIN  Pinta.Resources/Resources/LayersWidget.Visible.png
  42. BIN  Pinta.Resources/Resources/Menu.Adjustments.AutoLevel.png
  43. BIN  Pinta.Resources/Resources/Menu.Adjustments.BlackAndWhite.png
  44. BIN  Pinta.Resources/Resources/Menu.Adjustments.BrightnessAndContrast.png
  45. BIN  Pinta.Resources/Resources/Menu.Adjustments.Curves.png
  46. BIN  Pinta.Resources/Resources/Menu.Adjustments.HueAndSaturation.png
  47. BIN  Pinta.Resources/Resources/Menu.Adjustments.InvertColors.png
  48. BIN  Pinta.Resources/Resources/Menu.Adjustments.Levels.png
  49. BIN  Pinta.Resources/Resources/Menu.Adjustments.Sepia.png
  50. BIN  Pinta.Resources/Resources/Menu.Edit.Deselect.png
  51. BIN  Pinta.Resources/Resources/Menu.Edit.EraseSelection.png
  52. BIN  Pinta.Resources/Resources/Menu.Edit.FillSelection.png
  53. BIN  Pinta.Resources/Resources/Menu.Edit.InvertSelection.png
  54. BIN  Pinta.Resources/Resources/Menu.Edit.SelectAll.png
  55. BIN  Pinta.Resources/Resources/Menu.Help.Bug.png
  56. BIN  Pinta.Resources/Resources/Menu.Help.Website.png
  57. BIN  Pinta.Resources/Resources/Menu.Image.CanvasSize.png
  58. BIN  Pinta.Resources/Resources/Menu.Image.Crop.png
  59. BIN  Pinta.Resources/Resources/Menu.Image.Flatten.png
  60. BIN  Pinta.Resources/Resources/Menu.Image.FlipHorizontal.png
  61. BIN  Pinta.Resources/Resources/Menu.Image.FlipVertical.png
  62. BIN  Pinta.Resources/Resources/Menu.Image.Resize.png
  63. BIN  Pinta.Resources/Resources/Menu.Image.Rotate180CW.png
  64. BIN  Pinta.Resources/Resources/Menu.Image.Rotate90CCW.png
  65. BIN  Pinta.Resources/Resources/Menu.Image.Rotate90CW.png
  66. BIN  Pinta.Resources/Resources/Menu.Layers.AddNewLayer.png
  67. BIN  Pinta.Resources/Resources/Menu.Layers.DeleteLayer.png
  68. BIN  Pinta.Resources/Resources/Menu.Layers.DuplicateLayer.png
  69. BIN  Pinta.Resources/Resources/Menu.Layers.FlipHorizontal.png
  70. BIN  Pinta.Resources/Resources/Menu.Layers.FlipVertical.png
  71. BIN  Pinta.Resources/Resources/Menu.Layers.ImportFromFile.png
  72. BIN  Pinta.Resources/Resources/Menu.Layers.LayerProperties.png
  73. BIN  Pinta.Resources/Resources/Menu.Layers.MergeLayerDown.png
  74. BIN  Pinta.Resources/Resources/Menu.Layers.MoveLayerDown.png
  75. BIN  Pinta.Resources/Resources/Menu.Layers.MoveLayerUp.png
  76. BIN  Pinta.Resources/Resources/Menu.Layers.RotateZoom.png
  77. BIN  Pinta.Resources/Resources/Menu.View.ActualSize.png
  78. BIN  Pinta.Resources/Resources/Menu.View.Grid.png
  79. BIN  Pinta.Resources/Resources/Menu.View.Rulers.png
  80. BIN  Pinta.Resources/Resources/Menu.View.ZoomIn.png
  81. BIN  Pinta.Resources/Resources/Menu.View.ZoomOut.png
  82. BIN  Pinta.Resources/Resources/Menu.View.ZoomToSelection.png
  83. BIN  Pinta.Resources/Resources/Menu.View.ZoomToWindow.png
  84. BIN  Pinta.Resources/Resources/Pinta.png
  85. BIN  Pinta.Resources/Resources/StatusBar.CursorXY.png
  86. BIN  Pinta.Resources/Resources/Toolbar.MinusButton.png
  87. BIN  Pinta.Resources/Resources/Toolbar.PlusButton.png
  88. BIN  Pinta.Resources/Resources/Tools.CloneStamp.png
  89. BIN  Pinta.Resources/Resources/Tools.ColorPicker.png
  90. BIN  Pinta.Resources/Resources/Tools.Ellipse.png
  91. BIN  Pinta.Resources/Resources/Tools.EllipseSelect.png
  92. BIN  Pinta.Resources/Resources/Tools.Eraser.png
  93. BIN  Pinta.Resources/Resources/Tools.FreeformShape.png
  94. BIN  Pinta.Resources/Resources/Tools.Gradient.png
  95. BIN  Pinta.Resources/Resources/Tools.LassoSelect.png
  96. BIN  Pinta.Resources/Resources/Tools.Line.png
  97. BIN  Pinta.Resources/Resources/Tools.MagicWand.png
  98. BIN  Pinta.Resources/Resources/Tools.Move.png
  99. BIN  Pinta.Resources/Resources/Tools.MoveSelection.png
  100. BIN  Pinta.Resources/Resources/Tools.PaintBucket.png
  101. BIN  Pinta.Resources/Resources/Tools.Paintbrush.png
  102. BIN  Pinta.Resources/Resources/Tools.Pan.png
  103. BIN  Pinta.Resources/Resources/Tools.Pencil.png
  104. BIN  Pinta.Resources/Resources/Tools.Recolor.png
  105. BIN  Pinta.Resources/Resources/Tools.Rectangle.png
  106. BIN  Pinta.Resources/Resources/Tools.RectangleSelect.png
  107. BIN  Pinta.Resources/Resources/Tools.RoundedRectangle.png
  108. BIN  Pinta.Resources/Resources/Tools.Text.png
  109. BIN  Pinta.Resources/Resources/Tools.Zoom.png
  110. +52 −0 Pinta.sln
  111. +4 −0 Pinta/.gitignore
  112. +26 −0 Pinta/AssemblyInfo.cs
  113. +42 −0 Pinta/Main.cs
  114. +185 −0 Pinta/MainWindow.cs
  115. +85 −0 Pinta/Pinta.csproj
  116. +56 −0 Pinta/Tools/EllipseSelectTool.cs
  117. +64 −0 Pinta/Tools/EllipseTool.cs
  118. +154 −0 Pinta/Tools/EraserTool.cs
  119. +135 −0 Pinta/Tools/MoveSelectedTool.cs
  120. +86 −0 Pinta/Tools/MoveSelectionTool.cs
  121. +165 −0 Pinta/Tools/PaintBrushTool.cs
  122. +57 −0 Pinta/Tools/RectangleSelectTool.cs
  123. +60 −0 Pinta/Tools/RectangleTool.cs
  124. +60 −0 Pinta/Tools/RoundedRectangleTool.cs
  125. +82 −0 Pinta/Tools/SelectTool.cs
  126. +214 −0 Pinta/Tools/ShapeTool.cs
  127. +163 −0 Pinta/Tools/UnimplementedTools.cs
  128. +190 −0 Pinta/Widgets/ColorPaletteWidget.cs
  129. +224 −0 Pinta/Widgets/LayersListWidget.cs
  130. +319 −0 Pinta/gtk-gui/Pinta.MainWindow.cs
  131. +35 −0 Pinta/gtk-gui/generated.cs
  132. +338 −0 Pinta/gtk-gui/gui.stetic
4 .gitignore
@@ -0,0 +1,4 @@
+
+*.pidb
+*.suo
+*.userprefs
3  Pinta.Core/.gitignore
@@ -0,0 +1,3 @@
+/bin/
+/obj/
+*.user
115 Pinta.Core/Actions/AdjustmentsActions.cs
@@ -0,0 +1,115 @@
+//
+// AdjustmentsActions.cs
+//
+// Author:
+// Jonathan Pobst <monkey@jpobst.com>
+//
+// Copyright (c) 2010 Jonathan Pobst
+//
+// 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;
+
+namespace Pinta.Core
+{
+ public class AdjustmentsActions
+ {
+ public Gtk.Action AutoLevel { get; private set; }
+ public Gtk.Action BlackAndWhite { get; private set; }
+ public Gtk.Action BrightnessContrast { get; private set; }
+ public Gtk.Action Curves { get; private set; }
+ public Gtk.Action HueSaturation { get; private set; }
+ public Gtk.Action InvertColors { get; private set; }
+ public Gtk.Action Levels { get; private set; }
+ public Gtk.Action Posterize { get; private set; }
+ public Gtk.Action Sepia { get; private set; }
+
+ public AdjustmentsActions ()
+ {
+ Gtk.IconFactory fact = new Gtk.IconFactory ();
+ fact.Add ("Menu.Adjustments.AutoLevel.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Adjustments.AutoLevel.png")));
+ fact.Add ("Menu.Adjustments.BlackAndWhite.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Adjustments.BlackAndWhite.png")));
+ fact.Add ("Menu.Adjustments.BrightnessAndContrast.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Adjustments.BrightnessAndContrast.png")));
+ fact.Add ("Menu.Adjustments.Curves.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Adjustments.Curves.png")));
+ fact.Add ("Menu.Adjustments.HueAndSaturation.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Adjustments.HueAndSaturation.png")));
+ fact.Add ("Menu.Adjustments.InvertColors.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Adjustments.InvertColors.png")));
+ fact.Add ("Menu.Adjustments.Levels.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Adjustments.Levels.png")));
+ fact.Add ("Menu.Adjustments.Sepia.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Adjustments.Sepia.png")));
+ fact.AddDefault ();
+
+ AutoLevel = new Gtk.Action ("AutoLevel", Mono.Unix.Catalog.GetString ("Auto Level"), null, "Menu.Adjustments.AutoLevel.png");
+ BlackAndWhite = new Gtk.Action ("BlackAndWhite", Mono.Unix.Catalog.GetString ("Black and White"), null, "Menu.Adjustments.BlackAndWhite.png");
+ BrightnessContrast = new Gtk.Action ("BrightnessContrast", Mono.Unix.Catalog.GetString ("Brightness / Contrast"), null, "Menu.Adjustments.BrightnessAndContrast.png");
+ Curves = new Gtk.Action ("Curves", Mono.Unix.Catalog.GetString ("Curves"), null, "Menu.Adjustments.Curves.png");
+ HueSaturation = new Gtk.Action ("HueSaturation", Mono.Unix.Catalog.GetString ("Hue / Saturation"), null, "Menu.Adjustments.HueAndSaturation.png");
+ InvertColors = new Gtk.Action ("InvertColors", Mono.Unix.Catalog.GetString ("Invert Colors"), null, "Menu.Adjustments.InvertColors.png");
+ Levels = new Gtk.Action ("Levels", Mono.Unix.Catalog.GetString ("Levels"), null, "Menu.Adjustments.Levels.png");
+ Posterize = new Gtk.Action ("Posterize", Mono.Unix.Catalog.GetString ("Posterize"), null, null);
+ Sepia = new Gtk.Action ("Sepia", Mono.Unix.Catalog.GetString ("Sepia"), null, "Menu.Adjustments.Sepia.png");
+
+ AutoLevel.Sensitive = false;
+ BrightnessContrast.Sensitive = false;
+ Curves.Sensitive = false;
+ HueSaturation.Sensitive = false;
+ Levels.Sensitive = false;
+ Posterize.Sensitive = false;
+ }
+
+ #region Initialization
+ public void CreateMainMenu (Gtk.Menu menu)
+ {
+ menu.Remove (menu.Children[1]);
+
+ menu.Append (AutoLevel.CreateAcceleratedMenuItem (Gdk.Key.L, Gdk.ModifierType.ControlMask | Gdk.ModifierType.ShiftMask));
+ menu.Append (BlackAndWhite.CreateAcceleratedMenuItem (Gdk.Key.G, Gdk.ModifierType.ControlMask | Gdk.ModifierType.ShiftMask));
+ menu.Append (BrightnessContrast.CreateAcceleratedMenuItem (Gdk.Key.C, Gdk.ModifierType.ControlMask | Gdk.ModifierType.ShiftMask));
+ menu.Append (Curves.CreateAcceleratedMenuItem (Gdk.Key.M, Gdk.ModifierType.ControlMask | Gdk.ModifierType.ShiftMask));
+ menu.Append (HueSaturation.CreateAcceleratedMenuItem (Gdk.Key.U, Gdk.ModifierType.ControlMask | Gdk.ModifierType.ShiftMask));
+ menu.Append (InvertColors.CreateAcceleratedMenuItem (Gdk.Key.I, Gdk.ModifierType.ControlMask | Gdk.ModifierType.ShiftMask));
+ menu.Append (Levels.CreateAcceleratedMenuItem (Gdk.Key.L, Gdk.ModifierType.ControlMask));
+ menu.Append (Posterize.CreateAcceleratedMenuItem (Gdk.Key.P, Gdk.ModifierType.ControlMask | Gdk.ModifierType.ShiftMask));
+ menu.Append (Sepia.CreateAcceleratedMenuItem (Gdk.Key.E, Gdk.ModifierType.ControlMask | Gdk.ModifierType.ShiftMask));
+ }
+
+ public void RegisterHandlers ()
+ {
+ Sepia.Activated += HandleSepiaActivated;
+ InvertColors.Activated += HandleInvertColorsActivated;
+ BlackAndWhite.Activated += HandleBlackAndWhiteActivated;
+ }
+ #endregion
+
+ #region Action Handlers
+ private void HandleBlackAndWhiteActivated (object sender, EventArgs e)
+ {
+ PintaCore.Layers.Desaturate ();
+ }
+
+ private void HandleInvertColorsActivated (object sender, EventArgs e)
+ {
+ PintaCore.Layers.Invert ();
+ }
+
+ private void HandleSepiaActivated (object sender, EventArgs e)
+ {
+ PintaCore.Layers.Sepia ();
+ }
+ #endregion
+ }
+}
149 Pinta.Core/Actions/EditActions.cs
@@ -0,0 +1,149 @@
+//
+// EditActions.cs
+//
+// Author:
+// Jonathan Pobst <monkey@jpobst.com>
+//
+// Copyright (c) 2010 Jonathan Pobst
+//
+// 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 Gtk;
+
+namespace Pinta.Core
+{
+ public class EditActions
+ {
+ public Gtk.Action Undo { get; private set; }
+ public Gtk.Action Redo { get; private set; }
+ public Gtk.Action Cut { get; private set; }
+ public Gtk.Action Copy { get; private set; }
+ public Gtk.Action Paste { get; private set; }
+ public Gtk.Action PasteIntoNewLayer { get; private set; }
+ public Gtk.Action PasteIntoNewImage { get; private set; }
+ public Gtk.Action EraseSelection { get; private set; }
+ public Gtk.Action FillSelection { get; private set; }
+ public Gtk.Action InvertSelection { get; private set; }
+ public Gtk.Action SelectAll { get; private set; }
+ public Gtk.Action Deselect { get; private set; }
+
+ public EditActions ()
+ {
+ Gtk.IconFactory fact = new Gtk.IconFactory ();
+ fact.Add ("Menu.Edit.Deselect.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Edit.Deselect.png")));
+ fact.Add ("Menu.Edit.EraseSelection.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Edit.EraseSelection.png")));
+ fact.Add ("Menu.Edit.FillSelection.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Edit.FillSelection.png")));
+ fact.Add ("Menu.Edit.InvertSelection.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Edit.InvertSelection.png")));
+ fact.Add ("Menu.Edit.SelectAll.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Edit.SelectAll.png")));
+ fact.AddDefault ();
+
+ Undo = new Gtk.Action ("Undo", Mono.Unix.Catalog.GetString ("Undo"), null, "gtk-undo");
+ Redo = new Gtk.Action ("Redo", Mono.Unix.Catalog.GetString ("Redo"), null, "gtk-redo");
+ Cut = new Gtk.Action ("Cut", Mono.Unix.Catalog.GetString ("Cut"), null, "gtk-cut");
+ Copy = new Gtk.Action ("Copy", Mono.Unix.Catalog.GetString ("Copy"), null, "gtk-copy");
+ Paste = new Gtk.Action ("Paste", Mono.Unix.Catalog.GetString ("Paste"), null, "gtk-paste");
+ PasteIntoNewLayer = new Gtk.Action ("PasteIntoNewLayer", Mono.Unix.Catalog.GetString ("Paste Into New Layer"), null, "gtk-paste");
+ PasteIntoNewImage = new Gtk.Action ("PasteIntoNewImage", Mono.Unix.Catalog.GetString ("Paste Into New Image"), null, "gtk-paste");
+ EraseSelection = new Gtk.Action ("EraseSelection", Mono.Unix.Catalog.GetString ("Erase Selection"), null, "Menu.Edit.EraseSelection.png");
+ FillSelection = new Gtk.Action ("FillSelection", Mono.Unix.Catalog.GetString ("Fill Selection"), null, "Menu.Edit.FillSelection.png");
+ InvertSelection = new Gtk.Action ("InvertSelection", Mono.Unix.Catalog.GetString ("Invert Selection"), null, "Menu.Edit.InvertSelection.png");
+ SelectAll = new Gtk.Action ("SelectAll", Mono.Unix.Catalog.GetString ("Select All"), null, "Menu.Edit.SelectAll.png");
+ Deselect = new Gtk.Action ("Deselect", Mono.Unix.Catalog.GetString ("Deselect"), null, "Menu.Edit.Deselect.png");
+
+ Undo.Sensitive = false;
+ Redo.Sensitive = false;
+ Cut.Sensitive = false;
+ Copy.Sensitive = false;
+ Paste.Sensitive = false;
+ PasteIntoNewLayer.Sensitive = false;
+ PasteIntoNewImage.Sensitive = false;
+ InvertSelection.Sensitive = false;
+ }
+
+ #region Initialization
+ public void CreateMainMenu (Gtk.Menu menu)
+ {
+ menu.Remove (menu.Children[1]);
+
+ menu.Append (Undo.CreateAcceleratedMenuItem (Gdk.Key.Z, Gdk.ModifierType.ControlMask));
+ menu.Append (Redo.CreateAcceleratedMenuItem (Gdk.Key.Y, Gdk.ModifierType.ControlMask));
+ menu.AppendSeparator ();
+ menu.Append (Cut.CreateAcceleratedMenuItem (Gdk.Key.X, Gdk.ModifierType.ControlMask));
+ menu.Append (Copy.CreateAcceleratedMenuItem (Gdk.Key.C, Gdk.ModifierType.ControlMask));
+ menu.Append (Paste.CreateAcceleratedMenuItem (Gdk.Key.V, Gdk.ModifierType.ControlMask));
+ menu.Append (PasteIntoNewLayer.CreateAcceleratedMenuItem (Gdk.Key.V, Gdk.ModifierType.ShiftMask));
+ menu.Append (PasteIntoNewImage.CreateAcceleratedMenuItem (Gdk.Key.V, Gdk.ModifierType.Mod1Mask));
+ menu.AppendSeparator ();
+ menu.Append (EraseSelection.CreateAcceleratedMenuItem (Gdk.Key.Delete, Gdk.ModifierType.None));
+ menu.Append (FillSelection.CreateAcceleratedMenuItem (Gdk.Key.BackSpace, Gdk.ModifierType.None));
+ menu.Append (InvertSelection.CreateAcceleratedMenuItem (Gdk.Key.I, Gdk.ModifierType.ControlMask));
+ menu.Append (SelectAll.CreateAcceleratedMenuItem (Gdk.Key.A, Gdk.ModifierType.ControlMask));
+ menu.Append (Deselect.CreateAcceleratedMenuItem (Gdk.Key.D, Gdk.ModifierType.ControlMask));
+ }
+
+ public void RegisterHandlers ()
+ {
+ Deselect.Activated += HandlePintaCoreActionsEditDeselectActivated;
+ EraseSelection.Activated += HandlePintaCoreActionsEditEraseSelectionActivated;
+ SelectAll.Activated += HandlePintaCoreActionsEditSelectAllActivated;
+ FillSelection.Activated += HandlePintaCoreActionsEditFillSelectionActivated;
+ }
+ #endregion
+
+ #region Action Handlers
+ private void HandlePintaCoreActionsEditFillSelectionActivated (object sender, EventArgs e)
+ {
+ using (Cairo.Context g = new Cairo.Context (PintaCore.Layers.CurrentLayer.Surface)) {
+ g.AppendPath (PintaCore.Layers.SelectionPath);
+ g.Color = PintaCore.Palette.PrimaryColor;
+ g.Fill ();
+ }
+
+ PintaCore.Chrome.DrawingArea.GdkWindow.Invalidate ();
+ }
+
+ private void HandlePintaCoreActionsEditSelectAllActivated (object sender, EventArgs e)
+ {
+ PintaCore.Layers.ResetSelectionPath ();
+ PintaCore.Layers.ShowSelection = true;
+
+ PintaCore.Chrome.DrawingArea.GdkWindow.Invalidate ();
+ }
+
+ private void HandlePintaCoreActionsEditEraseSelectionActivated (object sender, EventArgs e)
+ {
+ using (Cairo.Context g = new Cairo.Context (PintaCore.Layers.CurrentLayer.Surface)) {
+ g.AppendPath (PintaCore.Layers.SelectionPath);
+ g.Operator = Cairo.Operator.Clear;
+ g.Fill ();
+ }
+
+ PintaCore.Chrome.DrawingArea.GdkWindow.Invalidate ();
+ }
+
+ private void HandlePintaCoreActionsEditDeselectActivated (object sender, EventArgs e)
+ {
+ PintaCore.Layers.ResetSelectionPath ();
+
+ PintaCore.Chrome.DrawingArea.GdkWindow.Invalidate ();
+ }
+ #endregion
+ }
+}
168 Pinta.Core/Actions/FileActions.cs
@@ -0,0 +1,168 @@
+//
+// FileActions.cs
+//
+// Author:
+// Jonathan Pobst <monkey@jpobst.com>
+//
+// Copyright (c) 2010 Jonathan Pobst
+//
+// 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 Gtk;
+using Gdk;
+
+namespace Pinta.Core
+{
+ public class FileActions
+ {
+ public Gtk.Action New { get; private set; }
+ public Gtk.Action Open { get; private set; }
+ public Gtk.Action OpenRecent { get; private set; }
+ public Gtk.Action Close { get; private set; }
+ public Gtk.Action Save { get; private set; }
+ public Gtk.Action SaveAs { get; private set; }
+ public Gtk.Action Print { get; private set; }
+ public Gtk.Action Exit { get; private set; }
+
+ public FileActions ()
+ {
+ New = new Gtk.Action ("New", Mono.Unix.Catalog.GetString ("New"), null, "gtk-new");
+ Open = new Gtk.Action ("Open", Mono.Unix.Catalog.GetString ("Open"), null, "gtk-open");
+ OpenRecent = new Gtk.Action ("OpenRecent", Mono.Unix.Catalog.GetString ("Open Recent"), null, "gtk-open");
+ Close = new Gtk.Action ("Close", Mono.Unix.Catalog.GetString ("Close"), null, "gtk-close");
+ Save = new Gtk.Action ("Save", Mono.Unix.Catalog.GetString ("Save"), null, "gtk-save");
+ SaveAs = new Gtk.Action ("SaveAs", Mono.Unix.Catalog.GetString ("Save As"), null, "gtk-save-as");
+ Print = new Gtk.Action ("Print", Mono.Unix.Catalog.GetString ("Print"), null, "gtk-print");
+ Exit = new Gtk.Action ("Exit", Mono.Unix.Catalog.GetString ("Exit"), null, "gtk-quit");
+
+ OpenRecent.Sensitive = false;
+ Save.Sensitive = false;
+ Close.Sensitive = false;
+ Print.Sensitive = false;
+ }
+
+ #region Initialization
+ public void CreateMainMenu (Gtk.Menu menu)
+ {
+ menu.Remove (menu.Children[1]);
+
+ menu.Append (New.CreateAcceleratedMenuItem (Gdk.Key.N, Gdk.ModifierType.ControlMask));
+ menu.Append (Open.CreateAcceleratedMenuItem (Gdk.Key.O, Gdk.ModifierType.ControlMask));
+ menu.Append (OpenRecent.CreateMenuItem ());
+ menu.Append (Close.CreateAcceleratedMenuItem (Gdk.Key.W, Gdk.ModifierType.ControlMask));
+ menu.AppendSeparator ();
+ menu.Append (Save.CreateAcceleratedMenuItem (Gdk.Key.S, Gdk.ModifierType.ControlMask));
+ menu.Append (SaveAs.CreateAcceleratedMenuItem (Gdk.Key.S, Gdk.ModifierType.ControlMask | Gdk.ModifierType.ShiftMask));
+ menu.AppendSeparator ();
+ menu.Append (Print.CreateAcceleratedMenuItem (Gdk.Key.P, Gdk.ModifierType.ControlMask));
+ menu.AppendSeparator ();
+ menu.Append (Exit.CreateAcceleratedMenuItem (Gdk.Key.Q, Gdk.ModifierType.ControlMask));
+ }
+
+ public void RegisterHandlers ()
+ {
+ New.Activated += HandlePintaCoreActionsFileNewActivated;
+ Open.Activated += HandlePintaCoreActionsFileOpenActivated;
+ SaveAs.Activated += HandlePintaCoreActionsFileSaveAsActivated;
+ Exit.Activated += HandlePintaCoreActionsFileExitActivated;
+ }
+ #endregion
+
+ #region Action Handlers
+ private void HandlePintaCoreActionsFileNewActivated (object sender, EventArgs e)
+ {
+ PintaCore.Layers.Clear ();
+
+ // Start with an empty white layer
+ Layer background = PintaCore.Layers.AddNewLayer ("Background");
+
+ using (Cairo.Context g = new Cairo.Context (background.Surface)) {
+ g.SetSourceRGB (255, 255, 255);
+ g.Paint ();
+ }
+
+ PintaCore.Chrome.DrawingArea.GdkWindow.Invalidate ();
+ }
+
+ private void HandlePintaCoreActionsFileOpenActivated (object sender, EventArgs e)
+ {
+ Gtk.FileChooserDialog fcd = new Gtk.FileChooserDialog ("Open Image File", null, FileChooserAction.Open, Gtk.Stock.Cancel, Gtk.ResponseType.Cancel, Gtk.Stock.Open, Gtk.ResponseType.Ok);
+
+ int response = fcd.Run ();
+
+ if (response == (int)Gtk.ResponseType.Ok) {
+
+ string file = fcd.Filename;
+
+ PintaCore.Layers.Clear ();
+
+ // Open the image and add it to the layers
+ Layer layer = PintaCore.Layers.AddNewLayer (System.IO.Path.GetFileName (file));
+
+ Pixbuf bg = new Pixbuf (file, (int)PintaCore.Workspace.ImageSize.X, (int)PintaCore.Workspace.ImageSize.Y, true);
+
+ using (Cairo.Context g = new Cairo.Context (layer.Surface)) {
+ CairoHelper.SetSourcePixbuf (g, bg, 0, 0);
+ g.Paint ();
+ }
+
+ bg.Dispose ();
+
+ PintaCore.Chrome.DrawingArea.GdkWindow.Invalidate ();
+ }
+
+ fcd.Destroy ();
+ }
+
+ private void HandlePintaCoreActionsFileSaveAsActivated (object sender, EventArgs e)
+ {
+ Gtk.FileChooserDialog fcd = new Gtk.FileChooserDialog ("Save Image File", null, FileChooserAction.Save, Gtk.Stock.Cancel, Gtk.ResponseType.Cancel, Gtk.Stock.Save, Gtk.ResponseType.Ok);
+
+ int response = fcd.Run ();
+
+ if (response == (int)Gtk.ResponseType.Ok) {
+
+ string file = fcd.Filename;
+
+ Cairo.ImageSurface surf = new Cairo.ImageSurface (Cairo.Format.Rgb24, (int)PintaCore.Workspace.ImageSize.X, (int)PintaCore.Workspace.ImageSize.Y);
+
+ using (Cairo.Context g = new Cairo.Context (surf)) {
+ foreach (var layer in PintaCore.Layers.GetLayersToPaint ()) {
+ g.SetSource (layer.Surface);
+ g.Paint ();
+
+ }
+ }
+
+ surf.WriteToPng (file);
+ (surf as IDisposable).Dispose ();
+ }
+
+ fcd.Destroy ();
+ }
+
+ private void HandlePintaCoreActionsFileExitActivated (object sender, EventArgs e)
+ {
+ (PintaCore.Layers.SelectionPath as IDisposable).Dispose ();
+ Application.Quit ();
+ }
+ #endregion
+ }
+}
65 Pinta.Core/Actions/HelpActions.cs
@@ -0,0 +1,65 @@
+//
+// HelpActions.cs
+//
+// Author:
+// Jonathan Pobst <monkey@jpobst.com>
+//
+// Copyright (c) 2010 Jonathan Pobst
+//
+// 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;
+
+namespace Pinta.Core
+{
+ public class HelpActions
+ {
+ public Gtk.Action Website { get; private set; }
+ public Gtk.Action Bugs { get; private set; }
+ public Gtk.Action About { get; private set; }
+
+ public HelpActions ()
+ {
+ Gtk.IconFactory fact = new Gtk.IconFactory ();
+ fact.Add ("Menu.Help.Bug.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Help.Bug.png")));
+ fact.Add ("Menu.Help.Website.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Help.Website.png")));
+ fact.AddDefault ();
+
+ Website = new Gtk.Action ("Website", Mono.Unix.Catalog.GetString ("Pinta Website"), null, "Menu.Help.Website.png");
+ Bugs = new Gtk.Action ("Bugs", Mono.Unix.Catalog.GetString ("File a Bug"), null, "Menu.Help.Bug.png");
+ About = new Gtk.Action ("About", Mono.Unix.Catalog.GetString ("About Pinta"), null, "gtk-about");
+
+ Website.Sensitive = false;
+ Bugs.Sensitive = false;
+ About.Sensitive = false;
+ }
+
+ #region Initialization
+ public void CreateMainMenu (Gtk.Menu menu)
+ {
+ menu.Remove (menu.Children[1]);
+
+ menu.Append (Website.CreateMenuItem ());
+ menu.Append (Bugs.CreateMenuItem ());
+ menu.AppendSeparator ();
+ menu.Append (About.CreateMenuItem ());
+ }
+ #endregion
+ }
+}
134 Pinta.Core/Actions/ImageActions.cs
@@ -0,0 +1,134 @@
+//
+// ImageActions.cs
+//
+// Author:
+// Jonathan Pobst <monkey@jpobst.com>
+//
+// Copyright (c) 2010 Jonathan Pobst
+//
+// 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;
+
+namespace Pinta.Core
+{
+ public class ImageActions
+ {
+ public Gtk.Action CropToSelection { get; private set; }
+ public Gtk.Action Resize { get; private set; }
+ public Gtk.Action CanvasSize { get; private set; }
+ public Gtk.Action FlipHorizontal { get; private set; }
+ public Gtk.Action FlipVertical { get; private set; }
+ public Gtk.Action RotateCW { get; private set; }
+ public Gtk.Action RotateCCW { get; private set; }
+ public Gtk.Action Rotate180 { get; private set; }
+ public Gtk.Action Flatten { get; private set; }
+
+ public ImageActions ()
+ {
+ Gtk.IconFactory fact = new Gtk.IconFactory ();
+ fact.Add ("Menu.Image.CanvasSize.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Image.CanvasSize.png")));
+ fact.Add ("Menu.Image.Crop.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Image.Crop.png")));
+ fact.Add ("Menu.Image.Flatten.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Image.Flatten.png")));
+ fact.Add ("Menu.Image.FlipHorizontal.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Image.FlipHorizontal.png")));
+ fact.Add ("Menu.Image.FlipVertical.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Image.FlipVertical.png")));
+ fact.Add ("Menu.Image.Resize.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Image.Resize.png")));
+ fact.Add ("Menu.Image.Rotate180CW.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Image.Rotate180CW.png")));
+ fact.Add ("Menu.Image.Rotate90CCW.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Image.Rotate90CCW.png")));
+ fact.Add ("Menu.Image.Rotate90CW.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Image.Rotate90CW.png")));
+ fact.AddDefault ();
+
+ CropToSelection = new Gtk.Action ("CropToSelection", Mono.Unix.Catalog.GetString ("Crop to Selection"), null, "Menu.Image.Crop.png");
+ Resize = new Gtk.Action ("Resize", Mono.Unix.Catalog.GetString ("Resize"), null, "Menu.Image.Resize.png");
+ CanvasSize = new Gtk.Action ("CanvasSize", Mono.Unix.Catalog.GetString ("Canvas Size"), null, "Menu.Image.CanvasSize.png");
+ FlipHorizontal = new Gtk.Action ("FlipHorizontal", Mono.Unix.Catalog.GetString ("Flip Horizontal"), null, "Menu.Image.FlipHorizontal.png");
+ FlipVertical = new Gtk.Action ("FlipVertical", Mono.Unix.Catalog.GetString ("Flip Vertical"), null, "Menu.Image.FlipVertical.png");
+ RotateCW = new Gtk.Action ("RotateCW", Mono.Unix.Catalog.GetString ("Rotate 90° Clockwise"), null, "Menu.Image.Rotate90CW.png");
+ RotateCCW = new Gtk.Action ("RotateCCW", Mono.Unix.Catalog.GetString ("Rotate 90° Counter-Clockwise"), null, "Menu.Image.Rotate90CCW.png");
+ Rotate180 = new Gtk.Action ("Rotate180", Mono.Unix.Catalog.GetString ("Rotate 180°"), null, "Menu.Image.Rotate180CW.png");
+ Flatten = new Gtk.Action ("Flatten", Mono.Unix.Catalog.GetString ("Flatten"), null, "Menu.Image.Flatten.png");
+
+ CropToSelection.Sensitive = false;
+ Resize.Sensitive = false;
+ CanvasSize.Sensitive = false;
+ }
+
+ #region Initialization
+ public void CreateMainMenu (Gtk.Menu menu)
+ {
+ menu.Remove (menu.Children[1]);
+
+ menu.Append (CropToSelection.CreateAcceleratedMenuItem (Gdk.Key.X, Gdk.ModifierType.ControlMask | Gdk.ModifierType.ShiftMask));
+ menu.Append (Resize.CreateAcceleratedMenuItem (Gdk.Key.R, Gdk.ModifierType.ControlMask));
+ menu.Append (CanvasSize.CreateAcceleratedMenuItem (Gdk.Key.R, Gdk.ModifierType.ControlMask | Gdk.ModifierType.ShiftMask));
+ menu.AppendSeparator ();
+ menu.Append (FlipHorizontal.CreateMenuItem ());
+ menu.Append (FlipVertical.CreateMenuItem ());
+ menu.AppendSeparator ();
+ menu.Append (RotateCW.CreateAcceleratedMenuItem (Gdk.Key.H, Gdk.ModifierType.ControlMask));
+ menu.Append (RotateCCW.CreateAcceleratedMenuItem (Gdk.Key.G, Gdk.ModifierType.ControlMask));
+ menu.Append (Rotate180.CreateAcceleratedMenuItem (Gdk.Key.J, Gdk.ModifierType.ControlMask));
+ menu.AppendSeparator ();
+ menu.Append (Flatten.CreateAcceleratedMenuItem (Gdk.Key.F, Gdk.ModifierType.ControlMask | Gdk.ModifierType.ShiftMask));
+ }
+
+ public void RegisterHandlers ()
+ {
+ FlipHorizontal.Activated += HandlePintaCoreActionsImageFlipHorizontalActivated;
+ FlipVertical.Activated += HandlePintaCoreActionsImageFlipVerticalActivated;
+ Rotate180.Activated += HandlePintaCoreActionsImageRotate180Activated;
+ Flatten.Activated += HandlePintaCoreActionsImageFlattenActivated;
+ RotateCW.Activated += HandlePintaCoreActionsImageRotateCWActivated;
+ RotateCCW.Activated += HandlePintaCoreActionsImageRotateCCWActivated;
+ }
+ #endregion
+
+ #region Action Handlers
+ private void HandlePintaCoreActionsImageRotateCCWActivated (object sender, EventArgs e)
+ {
+ PintaCore.Layers.RotateImageCCW ();
+ }
+
+ private void HandlePintaCoreActionsImageRotateCWActivated (object sender, EventArgs e)
+ {
+ PintaCore.Layers.RotateImageCW ();
+ }
+
+ private void HandlePintaCoreActionsImageFlattenActivated (object sender, EventArgs e)
+ {
+ PintaCore.Layers.FlattenImage ();
+ }
+
+ private void HandlePintaCoreActionsImageRotate180Activated (object sender, EventArgs e)
+ {
+ PintaCore.Layers.RotateImage180 ();
+ }
+
+ private void HandlePintaCoreActionsImageFlipVerticalActivated (object sender, EventArgs e)
+ {
+ PintaCore.Layers.FlipImageVertical ();
+ }
+
+ private void HandlePintaCoreActionsImageFlipHorizontalActivated (object sender, EventArgs e)
+ {
+ PintaCore.Layers.FlipImageHorizontal ();
+ }
+ #endregion
+ }
+}
224 Pinta.Core/Actions/LayerActions.cs
@@ -0,0 +1,224 @@
+//
+// LayerActions.cs
+//
+// Author:
+// Jonathan Pobst <monkey@jpobst.com>
+//
+// Copyright (c) 2010 Jonathan Pobst
+//
+// 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 Gdk;
+using Gtk;
+
+namespace Pinta.Core
+{
+ public class LayerActions
+ {
+ public Gtk.Action AddNewLayer { get; private set; }
+ public Gtk.Action DeleteLayer { get; private set; }
+ public Gtk.Action DuplicateLayer { get; private set; }
+ public Gtk.Action MergeLayerDown { get; private set; }
+ public Gtk.Action ImportFromFile { get; private set; }
+ public Gtk.Action FlipHorizontal { get; private set; }
+ public Gtk.Action FlipVertical { get; private set; }
+ public Gtk.Action RotateZoom { get; private set; }
+ public Gtk.Action MoveLayerUp { get; private set; }
+ public Gtk.Action MoveLayerDown { get; private set; }
+ public Gtk.Action Properties { get; private set; }
+
+ public LayerActions ()
+ {
+ Gtk.IconFactory fact = new Gtk.IconFactory ();
+ fact.Add ("Menu.Layers.AddNewLayer.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Layers.AddNewLayer.png")));
+ fact.Add ("Menu.Layers.DeleteLayer.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Layers.DeleteLayer.png")));
+ fact.Add ("Menu.Layers.DuplicateLayer.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Layers.DuplicateLayer.png")));
+ fact.Add ("Menu.Layers.MergeLayerDown.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Layers.MergeLayerDown.png")));
+ fact.Add ("Menu.Layers.MoveLayerDown.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Layers.MoveLayerDown.png")));
+ fact.Add ("Menu.Layers.MoveLayerUp.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Layers.MoveLayerUp.png")));
+ fact.Add ("Menu.Layers.FlipHorizontal.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Layers.FlipHorizontal.png")));
+ fact.Add ("Menu.Layers.FlipVertical.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Layers.FlipVertical.png")));
+ fact.Add ("Menu.Layers.ImportFromFile.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Layers.ImportFromFile.png")));
+ fact.Add ("Menu.Layers.LayerProperties.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Layers.LayerProperties.png")));
+ fact.Add ("Menu.Layers.RotateZoom.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.Layers.RotateZoom.png")));
+ fact.AddDefault ();
+
+ AddNewLayer = new Gtk.Action ("AddNewLayer", Mono.Unix.Catalog.GetString ("Add New Layer"), null, "Menu.Layers.AddNewLayer.png");
+ DeleteLayer = new Gtk.Action ("DeleteLayer", Mono.Unix.Catalog.GetString ("Delete Layer"), null, "Menu.Layers.DeleteLayer.png");
+ DuplicateLayer = new Gtk.Action ("DuplicateLayer", Mono.Unix.Catalog.GetString ("Duplicate Layer"), null, "Menu.Layers.DuplicateLayer.png");
+ MergeLayerDown = new Gtk.Action ("MergeLayerDown", Mono.Unix.Catalog.GetString ("Merge Layer Down"), null, "Menu.Layers.MergeLayerDown.png");
+ ImportFromFile = new Gtk.Action ("ImportFromFile", Mono.Unix.Catalog.GetString ("Import From File"), null, "Menu.Layers.ImportFromFile.png");
+ FlipHorizontal = new Gtk.Action ("FlipHorizontal", Mono.Unix.Catalog.GetString ("Flip Horizontal"), null, "Menu.Layers.FlipHorizontal.png");
+ FlipVertical = new Gtk.Action ("FlipVertical", Mono.Unix.Catalog.GetString ("Flip Vertical"), null, "Menu.Layers.FlipVertical.png");
+ RotateZoom = new Gtk.Action ("RotateZoom", Mono.Unix.Catalog.GetString ("Rotate / Zoom"), null, "Menu.Layers.RotateZoom.png");
+ MoveLayerUp = new Gtk.Action ("MoveLayerUp", Mono.Unix.Catalog.GetString ("Move Layer Up"), null, "Menu.Layers.MoveLayerUp.png");
+ MoveLayerDown = new Gtk.Action ("MoveLayerDown", Mono.Unix.Catalog.GetString ("Move Layer Down"), null, "Menu.Layers.MoveLayerDown.png");
+ Properties = new Gtk.Action ("Properties", Mono.Unix.Catalog.GetString ("Layer Properties"), null, "Menu.Layers.LayerProperties.png");
+
+ RotateZoom.Sensitive = false;
+ Properties.Sensitive = false;
+ }
+
+ #region Initialization
+ public void CreateMainMenu (Gtk.Menu menu)
+ {
+ menu.Remove (menu.Children[1]);
+
+ menu.Append (AddNewLayer.CreateAcceleratedMenuItem (Gdk.Key.N, Gdk.ModifierType.ControlMask | Gdk.ModifierType.ShiftMask));
+ menu.Append (DeleteLayer.CreateAcceleratedMenuItem (Gdk.Key.Delete, Gdk.ModifierType.ControlMask | Gdk.ModifierType.ShiftMask));
+ menu.Append (DuplicateLayer.CreateAcceleratedMenuItem (Gdk.Key.D, Gdk.ModifierType.ControlMask | Gdk.ModifierType.ShiftMask));
+ menu.Append (MergeLayerDown.CreateAcceleratedMenuItem (Gdk.Key.M, Gdk.ModifierType.ControlMask));
+ menu.Append (ImportFromFile.CreateMenuItem ());
+ menu.AppendSeparator ();
+ menu.Append (FlipHorizontal.CreateMenuItem ());
+ menu.Append (FlipVertical.CreateMenuItem ());
+ menu.Append (RotateZoom.CreateAcceleratedMenuItem (Gdk.Key.Z, Gdk.ModifierType.ControlMask | Gdk.ModifierType.ShiftMask));
+ menu.AppendSeparator ();
+ menu.Append (Properties.CreateAcceleratedMenuItem (Gdk.Key.F4, Gdk.ModifierType.None));
+ }
+
+ public void CreateLayerWindowToolBar (Gtk.Toolbar toolbar)
+ {
+ toolbar.AppendItem (AddNewLayer.CreateToolBarItem ());
+ toolbar.AppendItem (DeleteLayer.CreateToolBarItem ());
+ toolbar.AppendItem (DuplicateLayer.CreateToolBarItem ());
+ toolbar.AppendItem (MergeLayerDown.CreateToolBarItem ());
+ toolbar.AppendItem (MoveLayerUp.CreateToolBarItem ());
+ toolbar.AppendItem (MoveLayerDown.CreateToolBarItem ());
+ toolbar.AppendItem (Properties.CreateToolBarItem ());
+ }
+
+ public void RegisterHandlers ()
+ {
+ AddNewLayer.Activated += HandlePintaCoreActionsLayersAddNewLayerActivated;
+ DeleteLayer.Activated += HandlePintaCoreActionsLayersDeleteLayerActivated;
+ DuplicateLayer.Activated += HandlePintaCoreActionsLayersDuplicateLayerActivated;
+ MergeLayerDown.Activated += HandlePintaCoreActionsLayersMergeLayerDownActivated;
+ MoveLayerDown.Activated += HandlePintaCoreActionsLayersMoveLayerDownActivated;
+ MoveLayerUp.Activated += HandlePintaCoreActionsLayersMoveLayerUpActivated;
+ FlipHorizontal.Activated += HandlePintaCoreActionsLayersFlipHorizontalActivated;
+ FlipVertical.Activated += HandlePintaCoreActionsLayersFlipVerticalActivated;
+ ImportFromFile.Activated += HandlePintaCoreActionsLayersImportFromFileActivated;
+
+ PintaCore.Layers.LayerAdded += EnableOrDisableLayerActions;
+ PintaCore.Layers.LayerRemoved += EnableOrDisableLayerActions;
+ PintaCore.Layers.SelectedLayerChanged += EnableOrDisableLayerActions;
+
+ EnableOrDisableLayerActions (null, EventArgs.Empty);
+ }
+ #endregion
+
+ #region Action Handlers
+ private void EnableOrDisableLayerActions (object sender, EventArgs e)
+ {
+ if (PintaCore.Layers.Count > 1) {
+ PintaCore.Actions.Layers.DeleteLayer.Sensitive = true;
+ PintaCore.Actions.Image.Flatten.Sensitive = true;
+ } else {
+ PintaCore.Actions.Layers.DeleteLayer.Sensitive = false;
+ PintaCore.Actions.Image.Flatten.Sensitive = false;
+ }
+
+ if (PintaCore.Layers.CurrentLayerIndex > 0) {
+ PintaCore.Actions.Layers.MergeLayerDown.Sensitive = true;
+ PintaCore.Actions.Layers.MoveLayerDown.Sensitive = true;
+ } else {
+ PintaCore.Actions.Layers.MergeLayerDown.Sensitive = false;
+ PintaCore.Actions.Layers.MoveLayerDown.Sensitive = false;
+ }
+
+ if (PintaCore.Layers.CurrentLayerIndex < PintaCore.Layers.Count - 1)
+ PintaCore.Actions.Layers.MoveLayerUp.Sensitive = true;
+ else
+ PintaCore.Actions.Layers.MoveLayerUp.Sensitive = false;
+ }
+
+ private void HandlePintaCoreActionsLayersImportFromFileActivated (object sender, EventArgs e)
+ {
+ Gtk.FileChooserDialog fcd = new Gtk.FileChooserDialog ("Open Image File", null, FileChooserAction.Open, Gtk.Stock.Cancel, Gtk.ResponseType.Cancel, Gtk.Stock.Open, Gtk.ResponseType.Ok);
+
+ int response = fcd.Run ();
+
+ if (response == (int)Gtk.ResponseType.Ok) {
+
+ string file = fcd.Filename;
+
+ // Open the image and add it to the layers
+ Layer layer = PintaCore.Layers.AddNewLayer (System.IO.Path.GetFileName (file));
+
+ Pixbuf bg = new Pixbuf (file, (int)PintaCore.Workspace.ImageSize.X, (int)PintaCore.Workspace.ImageSize.Y, true);
+
+ using (Cairo.Context g = new Cairo.Context (layer.Surface)) {
+ CairoHelper.SetSourcePixbuf (g, bg, 0, 0);
+ g.Paint ();
+ }
+
+ bg.Dispose ();
+
+ PintaCore.Layers.SetCurrentLayer (layer);
+
+ PintaCore.Chrome.DrawingArea.GdkWindow.Invalidate ();
+ }
+
+ fcd.Destroy ();
+ }
+
+ private void HandlePintaCoreActionsLayersFlipVerticalActivated (object sender, EventArgs e)
+ {
+ PintaCore.Layers.FlipCurrentLayerVertical ();
+ }
+
+ private void HandlePintaCoreActionsLayersFlipHorizontalActivated (object sender, EventArgs e)
+ {
+ PintaCore.Layers.FlipCurrentLayerHorizontal ();
+ }
+
+ private void HandlePintaCoreActionsLayersMoveLayerUpActivated (object sender, EventArgs e)
+ {
+ PintaCore.Layers.MoveCurrentLayerUp ();
+ }
+
+ private void HandlePintaCoreActionsLayersMoveLayerDownActivated (object sender, EventArgs e)
+ {
+ PintaCore.Layers.MoveCurrentLayerDown ();
+ }
+
+ private void HandlePintaCoreActionsLayersMergeLayerDownActivated (object sender, EventArgs e)
+ {
+ PintaCore.Layers.MergeCurrentLayerDown ();
+ }
+
+ private void HandlePintaCoreActionsLayersDuplicateLayerActivated (object sender, EventArgs e)
+ {
+ PintaCore.Layers.DuplicateCurrentLayer ();
+ }
+
+ private void HandlePintaCoreActionsLayersDeleteLayerActivated (object sender, EventArgs e)
+ {
+ PintaCore.Layers.DeleteCurrentLayer ();
+ }
+
+ private void HandlePintaCoreActionsLayersAddNewLayerActivated (object sender, EventArgs e)
+ {
+ PintaCore.Layers.AddNewLayer (string.Empty);
+ }
+ #endregion
+ }
+}
148 Pinta.Core/Actions/ViewActions.cs
@@ -0,0 +1,148 @@
+//
+// ViewActions.cs
+//
+// Author:
+// Jonathan Pobst <monkey@jpobst.com>
+//
+// Copyright (c) 2010 Jonathan Pobst
+//
+// 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;
+
+
+namespace Pinta.Core
+{
+ public class ViewActions
+ {
+ public Gtk.Action ZoomIn { get; private set; }
+ public Gtk.Action ZoomOut { get; private set; }
+ public Gtk.Action ZoomToWindow { get; private set; }
+ public Gtk.Action ZoomToSelection { get; private set; }
+ public Gtk.Action ActualSize { get; private set; }
+ public Gtk.Action PixelGrid { get; private set; }
+ public Gtk.Action Rulers { get; private set; }
+ public Gtk.Action Pixels { get; private set; }
+ public Gtk.Action Inches { get; private set; }
+ public Gtk.Action Centimeters { get; private set; }
+
+ public ToolBarComboBox ZoomComboBox { get; private set; }
+
+ public ViewActions ()
+ {
+ Gtk.IconFactory fact = new Gtk.IconFactory ();
+ fact.Add ("Menu.View.ActualSize.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.View.ActualSize.png")));
+ fact.Add ("Menu.View.Grid.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.View.Grid.png")));
+ fact.Add ("Menu.View.Rulers.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.View.Rulers.png")));
+ fact.Add ("Menu.View.ZoomIn.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.View.ZoomIn.png")));
+ fact.Add ("Menu.View.ZoomOut.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.View.ZoomOut.png")));
+ fact.Add ("Menu.View.ZoomToSelection.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.View.ZoomToSelection.png")));
+ fact.Add ("Menu.View.ZoomToWindow.png", new Gtk.IconSet (PintaCore.Resources.GetIcon ("Menu.View.ZoomToWindow.png")));
+ fact.AddDefault ();
+
+ ZoomIn = new Gtk.Action ("ZoomIn", Mono.Unix.Catalog.GetString ("Zoom In"), null, "Menu.View.ZoomIn.png");
+ ZoomOut = new Gtk.Action ("ZoomOut", Mono.Unix.Catalog.GetString ("Zoom Out"), null, "Menu.View.ZoomOut.png");
+ ZoomToWindow = new Gtk.Action ("ZoomToWindow", Mono.Unix.Catalog.GetString ("Zoom to Window"), null, "Menu.View.ZoomToWindow.png");
+ ZoomToSelection = new Gtk.Action ("ZoomToSelection", Mono.Unix.Catalog.GetString ("Zoom to Selection"), null, "Menu.View.ZoomToSelection.png");
+ ActualSize = new Gtk.Action ("ActualSize", Mono.Unix.Catalog.GetString ("Actual Size"), null, "Menu.View.ActualSize.png");
+ PixelGrid = new Gtk.Action ("PixelGrid", Mono.Unix.Catalog.GetString ("Pixel Grid"), null, "Menu.View.Grid.png");
+ Rulers = new Gtk.Action ("Rulers", Mono.Unix.Catalog.GetString ("Rulers"), null, "Menu.View.Rulers.png");
+ Pixels = new Gtk.Action ("Pixels", Mono.Unix.Catalog.GetString ("Pixels"), null, null);
+ Inches = new Gtk.Action ("Inches", Mono.Unix.Catalog.GetString ("Inches"), null, null);
+ Centimeters = new Gtk.Action ("Centimeters", Mono.Unix.Catalog.GetString ("Centimeters"), null, null);
+
+ ZoomComboBox = new ToolBarComboBox (75, 11, "3600%", "2400%", "1600%", "1200%", "800%", "700%", "600%", "500%", "400%", "300%", "200%", "100%", "66%", "50%", "33%", "25%", "16%", "12%", "8%", "5%", "Window");
+
+ ZoomToWindow.Sensitive = false;
+ ZoomToSelection.Sensitive = false;
+ PixelGrid.Sensitive = false;
+ Rulers.Sensitive = false;
+ Pixels.Sensitive = false;
+ Inches.Sensitive = false;
+ Centimeters.Sensitive = false;
+ }
+
+ #region Initialization
+ public void CreateMainMenu (Gtk.Menu menu)
+ {
+ menu.Remove (menu.Children[1]);
+
+ menu.Append (ZoomIn.CreateAcceleratedMenuItem (Gdk.Key.plus, Gdk.ModifierType.ControlMask));
+ menu.Append (ZoomOut.CreateAcceleratedMenuItem (Gdk.Key.minus, Gdk.ModifierType.ControlMask));
+ menu.Append (ZoomToWindow.CreateAcceleratedMenuItem (Gdk.Key.B, Gdk.ModifierType.ControlMask));
+ menu.Append (ZoomToSelection.CreateAcceleratedMenuItem (Gdk.Key.B, Gdk.ModifierType.ControlMask | Gdk.ModifierType.ShiftMask));
+ menu.Append (ActualSize.CreateAcceleratedMenuItem (Gdk.Key.A, Gdk.ModifierType.ControlMask | Gdk.ModifierType.ShiftMask));
+ menu.AppendSeparator ();
+ menu.Append (PixelGrid.CreateMenuItem ());
+ menu.Append (Rulers.CreateMenuItem ());
+ menu.AppendSeparator ();
+ menu.Append (Pixels.CreateMenuItem ());
+ menu.Append (Inches.CreateMenuItem ());
+ menu.Append (Centimeters.CreateMenuItem ());
+ }
+
+ public void CreateToolBar (Gtk.Toolbar toolbar)
+ {
+ toolbar.AppendItem (new Gtk.SeparatorToolItem ());
+ toolbar.AppendItem (ZoomOut.CreateToolBarItem ());
+ toolbar.AppendItem (ZoomComboBox);
+ toolbar.AppendItem (ZoomIn.CreateToolBarItem ());
+ }
+
+ public void RegisterHandlers ()
+ {
+ ZoomIn.Activated += HandlePintaCoreActionsViewZoomInActivated;
+ ZoomOut.Activated += HandlePintaCoreActionsViewZoomOutActivated;
+ ZoomComboBox.ComboBox.Changed += HandlePintaCoreActionsViewZoomComboBoxComboBoxChanged;
+ ActualSize.Activated += HandlePintaCoreActionsViewActualSizeActivated;
+ }
+ #endregion
+
+ #region Action Handlers
+ private void HandlePintaCoreActionsViewActualSizeActivated (object sender, EventArgs e)
+ {
+ PintaCore.Workspace.Scale = 1.0;
+ }
+
+ private void HandlePintaCoreActionsViewZoomComboBoxComboBoxChanged (object sender, EventArgs e)
+ {
+ string text = PintaCore.Actions.View.ZoomComboBox.ComboBox.ActiveText;
+
+ if (text == "Window")
+ PintaCore.Workspace.Scale = 1.0;
+
+ text = text.Trim ('%');
+
+ double percent = double.Parse (text) / 100.0;
+
+ PintaCore.Workspace.Scale = percent;
+ }
+
+ private void HandlePintaCoreActionsViewZoomOutActivated (object sender, EventArgs e)
+ {
+ PintaCore.Workspace.ZoomOut ();
+ }
+
+ private void HandlePintaCoreActionsViewZoomInActivated (object sender, EventArgs e)
+ {
+ PintaCore.Workspace.ZoomIn ();
+ }
+ #endregion
+ }
+}
26 Pinta.Core/AssemblyInfo.cs
@@ -0,0 +1,26 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+
+[assembly: AssemblyTitle("Pinta.Core")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+
+[assembly: AssemblyVersion("1.0.*")]
+
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
139 Pinta.Core/Classes/BaseTool.cs
@@ -0,0 +1,139 @@
+//
+// BaseTool.cs
+//
+// Author:
+// Jonathan Pobst <monkey@jpobst.com>
+//
+// Copyright (c) 2010 Jonathan Pobst
+//
+// 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 Gtk;
+using System.IO;
+
+namespace Pinta.Core
+{
+ public abstract class BaseTool
+ {
+ protected ToggleToolButton tool_item;
+ protected ToolItem tool_label;
+ protected ToolItem tool_image;
+ protected ToolItem tool_sep;
+
+ protected BaseTool ()
+ {
+ }
+
+ public virtual string Name { get { throw new ApplicationException ("Tool didn't override Name"); } }
+ public virtual string Icon { get { throw new ApplicationException ("Tool didn't override Icon"); } }
+ public virtual string ToolTip { get { throw new ApplicationException ("Tool didn't override ToolTip"); } }
+ public virtual string StatusBarText { get { return string.Empty; } }
+ public virtual ToggleToolButton ToolItem { get { if (tool_item == null) tool_item = CreateToolButton (); return tool_item; } }
+ public virtual bool Enabled { get { return false; } }
+
+ #region Public Methods
+ public void DoMouseMove (object o, MotionNotifyEventArgs args, Cairo.PointD point)
+ {
+ OnMouseMove (o, args, point);
+ }
+
+ public void DoBuildToolBar (Toolbar tb)
+ {
+ OnBuildToolBar (tb);
+ }
+
+ public void DoClearToolBar (Toolbar tb)
+ {
+ OnClearToolBar (tb);
+ }
+
+ public void DoMouseDown (DrawingArea canvas, ButtonPressEventArgs args, Cairo.PointD point)
+ {
+ OnMouseDown (canvas, args, point);
+ }
+
+ public void DoMouseUp (DrawingArea canvas, ButtonReleaseEventArgs args, Cairo.PointD point)
+ {
+ OnMouseUp (canvas, args, point);
+ }
+
+ public void DoDeactivated ()
+ {
+ OnDeactivated ();
+ }
+ #endregion
+
+ #region Protected Methods
+ protected virtual void OnMouseMove (object o, Gtk.MotionNotifyEventArgs args, Cairo.PointD point)
+ {
+ }
+
+ protected virtual void OnBuildToolBar (Toolbar tb)
+ {
+ if (tool_label == null)
+ tool_label = new ToolBarLabel (" Tool: ");
+
+ tb.AppendItem (tool_label);
+
+ if (tool_image == null)
+ tool_image = new ToolBarImage (Icon);
+
+ tb.AppendItem (tool_image);
+
+ if (tool_sep == null)
+ tool_sep = new SeparatorToolItem ();
+
+ tb.AppendItem (tool_sep);
+ }
+
+ protected virtual void OnClearToolBar (Toolbar tb)
+ {
+ while (tb.NItems > 0)
+ tb.Remove (tb.Children[tb.NItems - 1]);
+ }
+
+ protected virtual void OnMouseDown (DrawingArea canvas, Gtk.ButtonPressEventArgs args, Cairo.PointD point)
+ {
+ }
+
+ protected virtual void OnMouseUp (DrawingArea canvas, Gtk.ButtonReleaseEventArgs args, Cairo.PointD point)
+ {
+ }
+
+ protected virtual void OnDeactivated ()
+ {
+ }
+
+ protected virtual ToggleToolButton CreateToolButton ()
+ {
+ Image i2 = new Image (PintaCore.Resources.GetIcon (Icon));
+ i2.Show ();
+
+ ToggleToolButton tool_item = new ToggleToolButton ();
+ tool_item.IconWidget = i2;
+ tool_item.Show ();
+ tool_item.Label = Name;
+ tool_item.TooltipText = Name;
+
+ return tool_item;
+ }
+ #endregion
+ }
+}
200 Pinta.Core/Classes/Layer.cs
@@ -0,0 +1,200 @@
+//
+// Layer.cs
+//
+// Author:
+// Jonathan Pobst <monkey@jpobst.com>
+//
+// Copyright (c) 2010 Jonathan Pobst
+//
+// 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 Cairo;
+
+namespace Pinta.Core
+{
+ public class Layer
+ {
+ public ImageSurface Surface { get; set; }
+ public double Opacity { get; set; }
+ public bool Hidden { get; set; }
+ public string Name { get; set; }
+ public bool Tiled { get; set; }
+ public PointD Offset { get; set; }
+
+ public Layer () : this (null)
+ {
+ }
+
+ public Layer (ImageSurface surface) : this (surface, false, 1f, "")
+ {
+ }
+
+ public Layer (ImageSurface surface, bool hidden, double opacity, string name)
+ {
+ Surface = surface;
+ Hidden = hidden;
+ Opacity = opacity;
+ Name = name;
+ Offset = new PointD (0, 0);
+ }
+
+ public void Clear ()
+ {
+ using (Context g = new Context (Surface)) {
+ g.Operator = Operator.Clear;
+ g.Paint ();
+ }
+ }
+
+ public void FlipHorizontal ()
+ {
+ Layer dest = PintaCore.Layers.CreateLayer ();
+
+ using (Cairo.Context g = new Cairo.Context (dest.Surface)) {
+ g.Matrix = new Matrix (-1, 0, 0, 1, Surface.Width, 0);
+ g.SetSource (Surface);
+
+ g.Paint ();
+ }
+
+ Surface old = Surface;
+ Surface = dest.Surface;
+ (old as IDisposable).Dispose ();
+ }
+
+ public void FlipVertical ()
+ {
+ Layer dest = PintaCore.Layers.CreateLayer ();
+
+ using (Cairo.Context g = new Cairo.Context (dest.Surface)) {
+ g.Matrix = new Matrix (1, 0, 0, -1, 0, Surface.Height);
+ g.SetSource (Surface);
+
+ g.Paint ();
+ }
+
+ Surface old = Surface;
+ Surface = dest.Surface;
+ (old as IDisposable).Dispose ();
+ }
+
+ public void Rotate180 ()
+ {
+ Layer dest = PintaCore.Layers.CreateLayer ();
+
+ using (Cairo.Context g = new Cairo.Context (dest.Surface)) {
+ g.Matrix = new Matrix (-1, 0, 0, -1, Surface.Width, Surface.Height);
+ g.SetSource (Surface);
+
+ g.Paint ();
+ }
+
+ Surface old = Surface;
+ Surface = dest.Surface;
+ (old as IDisposable).Dispose ();
+ }
+
+ public void Rotate90CW ()
+ {
+ double w = PintaCore.Workspace.ImageSize.X;
+ double h = PintaCore.Workspace.ImageSize.Y;
+
+ Layer dest = PintaCore.Layers.CreateLayer ("", (int)h, (int)w);
+
+ using (Cairo.Context g = new Cairo.Context (dest.Surface)) {
+ g.Translate (h / 2, w / 2);
+ g.Rotate (Math.PI / 2);
+ g.Translate (-w / 2, -h / 2);
+ g.SetSource (Surface);
+
+ g.Paint ();
+ }
+
+ Surface old = Surface;
+ Surface = dest.Surface;
+ (old as IDisposable).Dispose ();
+ }
+
+ public void Rotate90CCW ()
+ {
+ double w = PintaCore.Workspace.ImageSize.X;
+ double h = PintaCore.Workspace.ImageSize.Y;
+
+ Layer dest = PintaCore.Layers.CreateLayer ("", (int)h, (int)w);
+
+ using (Cairo.Context g = new Cairo.Context (dest.Surface)) {
+ g.Translate (h / 2, w / 2);
+ g.Rotate (Math.PI / -2);
+ g.Translate (-w / 2, -h / 2);
+ g.SetSource (Surface);
+
+ g.Paint ();
+ }
+
+ Surface old = Surface;
+ Surface = dest.Surface;
+ (old as IDisposable).Dispose ();
+ }
+
+ public unsafe void Sepia ()
+ {
+ Desaturate ();
+
+ UnaryPixelOp op = new UnaryPixelOps.Level(
+ ColorBgra.Black,
+ ColorBgra.White,
+ new float[] { 1.2f, 1.0f, 0.8f },
+ ColorBgra.Black,
+ ColorBgra.White);
+
+ ColorBgra *dstPtr = (ColorBgra*)Surface.DataPtr;
+ int len = Surface.Data.Length / 4;
+
+ op.Apply (dstPtr, len);
+ }
+
+ public unsafe void Invert ()
+ {
+ ColorBgra *dstPtr = (ColorBgra*)Surface.DataPtr;
+ int len = Surface.Data.Length / 4;
+
+ for (int i = 0; i < len; i++) {
+ if (dstPtr->A != 0)
+ *dstPtr = (ColorBgra.FromBgra((byte)(255 - dstPtr->B), (byte)(255 - dstPtr->G), (byte)(255 - dstPtr->R), dstPtr->A));
+ dstPtr++;
+ }
+ }
+
+ public unsafe void Desaturate ()
+ {
+ ColorBgra *dstPtr = (ColorBgra*)Surface.DataPtr;
+ int len = Surface.Data.Length / 4;
+
+ for (int i = 0; i < len; i++) {
+ byte ib = dstPtr->GetIntensityByte();
+
+ dstPtr->R = ib;
+ dstPtr->G = ib;
+ dstPtr->B = ib;
+ dstPtr++;
+ }
+ }
+ }
+}
1,808 Pinta.Core/Effects/ColorBgra.cs
@@ -0,0 +1,1808 @@
+/////////////////////////////////////////////////////////////////////////////////
+// Paint.NET //
+// Copyright (C) Rick Brewster, Tom Jackson, and past contributors. //
+// Portions Copyright (C) Microsoft Corporation. All Rights Reserved. //
+// See src/Resources/Files/License.txt for full licensing and attribution //
+// details. //
+// . //
+/////////////////////////////////////////////////////////////////////////////////
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+namespace Pinta.Core
+{
+ /// <summary>
+ /// This is our pixel format that we will work with. It is always 32-bits / 4-bytes and is
+ /// always laid out in BGRA order.
+ /// Generally used with the Surface class.
+ /// </summary>
+ [Serializable]
+ [StructLayout(LayoutKind.Explicit)]
+ public struct ColorBgra
+ {
+ [FieldOffset(0)]
+ public byte B;
+
+ [FieldOffset(1)]
+ public byte G;
+
+ [FieldOffset(2)]
+ public byte R;
+
+ [FieldOffset(3)]
+ public byte A;
+
+ /// <summary>
+ /// Lets you change B, G, R, and A at the same time.
+ /// </summary>
+ [NonSerialized]
+ [FieldOffset(0)]
+ public uint Bgra;
+
+ public const int BlueChannel = 0;
+ public const int GreenChannel = 1;
+ public const int RedChannel = 2;
+ public const int AlphaChannel = 3;
+
+ public const int SizeOf = 4;
+
+ public static ColorBgra ParseHexString(string hexString)
+ {
+ uint value = Convert.ToUInt32(hexString, 16);
+ return ColorBgra.FromUInt32(value);
+ }
+
+ public string ToHexString()
+ {
+ int rgbNumber = (this.R << 16) | (this.G << 8) | this.B;
+ string colorString = Convert.ToString(rgbNumber, 16);
+
+ while (colorString.Length < 6)
+ {
+ colorString = "0" + colorString;
+ }
+
+ string alphaString = System.Convert.ToString(this.A, 16);
+
+ while (alphaString.Length < 2)
+ {
+ alphaString = "0" + alphaString;
+ }
+
+ colorString = alphaString + colorString;
+
+ return colorString.ToUpper();
+ }
+
+ /// <summary>
+ /// Gets or sets the byte value of the specified color channel.
+ /// </summary>
+ public unsafe byte this[int channel]
+ {
+ get
+ {
+ if (channel < 0 || channel > 3)
+ {
+ throw new ArgumentOutOfRangeException("channel", channel, "valid range is [0,3]");
+ }
+
+ fixed (byte *p = &B)
+ {
+ return p[channel];
+ }
+ }
+
+ set
+ {
+ if (channel < 0 || channel > 3)
+ {
+ throw new ArgumentOutOfRangeException("channel", channel, "valid range is [0,3]");
+ }
+
+ fixed (byte *p = &B)
+ {
+ p[channel] = value;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets the luminance intensity of the pixel based on the values of the red, green, and blue components. Alpha is ignored.
+ /// </summary>
+ /// <returns>A value in the range 0 to 1 inclusive.</returns>
+ public double GetIntensity()
+ {
+ return ((0.114 * (double)B) + (0.587 * (double)G) + (0.299 * (double)R)) / 255.0;
+ }
+
+ /// <summary>
+ /// Gets the luminance intensity of the pixel based on the values of the red, green, and blue components. Alpha is ignored.
+ /// </summary>
+ /// <returns>A value in the range 0 to 255 inclusive.</returns>
+ public byte GetIntensityByte()
+ {
+ return (byte)((7471 * B + 38470 * G + 19595 * R) >> 16);
+ }
+
+ /// <summary>
+ /// Returns the maximum value out of the B, G, and R values. Alpha is ignored.
+ /// </summary>
+ /// <returns></returns>
+ public byte GetMaxColorChannelValue()
+ {
+ return Math.Max(this.B, Math.Max(this.G, this.R));
+ }
+
+ /// <summary>
+ /// Returns the average of the B, G, and R values. Alpha is ignored.
+ /// </summary>
+ /// <returns></returns>
+ public byte GetAverageColorChannelValue()
+ {
+ return (byte)((this.B + this.G + this.R) / 3);
+ }
+
+ /// <summary>
+ /// Compares two ColorBgra instance to determine if they are equal.
+ /// </summary>
+ public static bool operator == (ColorBgra lhs, ColorBgra rhs)
+ {
+ return lhs.Bgra == rhs.Bgra;
+ }
+
+ /// <summary>
+ /// Compares two ColorBgra instance to determine if they are not equal.
+ /// </summary>
+ public static bool operator != (ColorBgra lhs, ColorBgra rhs)
+ {
+ return lhs.Bgra != rhs.Bgra;
+ }
+
+ /// <summary>
+ /// Compares two ColorBgra instance to determine if they are equal.
+ /// </summary>
+ public override bool Equals(object obj)
+ {
+
+ if (obj != null && obj is ColorBgra && ((ColorBgra)obj).Bgra == this.Bgra)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Returns a hash code for this color value.
+ /// </summary>
+ /// <returns></returns>
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ return (int)Bgra;
+ }
+ }
+
+ /// <summary>
+ /// Gets the equivalent GDI+ PixelFormat.
+ /// </summary>
+ /// <remarks>
+ /// This property always returns PixelFormat.Format32bppArgb.
+ /// </remarks>
+// public static PixelFormat PixelFormat
+// {
+// get
+// {
+// return PixelFormat.Format32bppArgb;
+// }
+// }
+
+ /// <summary>
+ /// Returns a new ColorBgra with the same color values but with a new alpha component value.
+ /// </summary>
+ public ColorBgra NewAlpha(byte newA)
+ {
+ return ColorBgra.FromBgra(B, G, R, newA);
+ }
+
+ /// <summary>
+ /// Creates a new ColorBgra instance with the given color and alpha values.
+ /// </summary>
+ [Obsolete ("Use FromBgra() instead (make sure to swap the order of your b and r parameters)")]
+ public static ColorBgra FromRgba(byte r, byte g, byte b, byte a)
+ {
+ return FromBgra(b, g, r, a);
+ }
+
+ /// <summary>
+ /// Creates a new ColorBgra instance with the given color values, and 255 for alpha.
+ /// </summary>
+ [Obsolete ("Use FromBgr() instead (make sure to swap the order of your b and r parameters)")]
+ public static ColorBgra FromRgb(byte r, byte g, byte b)
+ {
+ return FromBgr(b, g, r);
+ }
+
+ /// <summary>
+ /// Creates a new ColorBgra instance with the given color and alpha values.
+ /// </summary>
+ public static ColorBgra FromBgra(byte b, byte g, byte r, byte a)
+ {
+ ColorBgra color = new ColorBgra();
+ color.Bgra = BgraToUInt32(b, g, r, a);
+ return color;
+ }
+
+ /// <summary>
+ /// Creates a new ColorBgra instance with the given color and alpha values.
+ /// </summary>
+ public static ColorBgra FromBgraClamped(int b, int g, int r, int a)
+ {
+ return FromBgra(
+ ClampToByte(b),
+ ClampToByte(g),
+ ClampToByte(r),
+ ClampToByte(a));
+ }
+
+ /// <summary>
+ /// Creates a new ColorBgra instance with the given color and alpha values.
+ /// </summary>
+ public static ColorBgra FromBgraClamped(float b, float g, float r, float a)
+ {
+ return FromBgra(
+ ClampToByte(b),
+ ClampToByte(g),
+ ClampToByte(r),
+ ClampToByte(a));
+ }
+
+ public static byte ClampToByte(float x)
+ {
+ if (x > 255)
+ {
+ return 255;
+ }
+ else if (x < 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return (byte)x;
+ }
+ }
+ /// <summary>
+ /// Packs color and alpha values into a 32-bit integer.
+ /// </summary>
+ public static UInt32 BgraToUInt32(byte b, byte g, byte r, byte a)
+ {
+ return (uint)b + ((uint)g << 8) + ((uint)r << 16) + ((uint)a << 24);
+ }
+
+ /// <summary>
+ /// Packs color and alpha values into a 32-bit integer.
+ /// </summary>
+ public static UInt32 BgraToUInt32(int b, int g, int r, int a)
+ {
+ return (uint)b + ((uint)g << 8) + ((uint)r << 16) + ((uint)a << 24);
+ }
+
+ /// <summary>
+ /// Creates a new ColorBgra instance with the given color values, and 255 for alpha.
+ /// </summary>
+ public static ColorBgra FromBgr(byte b, byte g, byte r)
+ {
+ return FromBgra(b, g, r, 255);
+ }
+
+ /// <summary>
+ /// Constructs a new ColorBgra instance with the given 32-bit value.
+ /// </summary>
+ public static ColorBgra FromUInt32(UInt32 bgra)
+ {
+ ColorBgra color = new ColorBgra();
+ color.Bgra = bgra;
+ return color;
+ }
+
+ public static byte ClampToByte(int x)
+ {
+ if (x > 255)
+ {
+ return 255;
+ }
+ else if (x < 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return (byte)x;
+ }
+ }
+ /// <summary>
+ /// Constructs a new ColorBgra instance from the values in the given Color instance.
+ /// </summary>
+// public static ColorBgra FromColor(Color c)
+// {
+// return FromBgra(c.B, c.G, c.R, c.A);
+// }
+
+ /// <summary>
+ /// Converts this ColorBgra instance to a Color instance.
+ /// </summary>
+// public Color ToColor()
+// {
+// return Color.FromArgb(A, R, G, B);
+// }
+
+ /// <summary>
+ /// Smoothly blends between two colors.
+ /// </summary>
+// public static ColorBgra Blend(ColorBgra ca, ColorBgra cb, byte cbAlpha)
+// {
+// uint caA = (uint)Utility.FastScaleByteByByte((byte)(255 - cbAlpha), ca.A);
+// uint cbA = (uint)Utility.FastScaleByteByByte(cbAlpha, cb.A);
+// uint cbAT = caA + cbA;
+//
+// uint r;
+// uint g;
+// uint b;
+//
+// if (cbAT == 0)
+// {
+// r = 0;
+// g = 0;
+// b = 0;
+// }
+// else
+// {
+// r = ((ca.R * caA) + (cb.R * cbA)) / cbAT;
+// g = ((ca.G * caA) + (cb.G * cbA)) / cbAT;
+// b = ((ca.B * caA) + (cb.B * cbA)) / cbAT;
+// }
+//
+// return ColorBgra.FromBgra((byte)b, (byte)g, (byte)r, (byte)cbAT);
+// }
+
+ /// <summary>
+ /// Linearly interpolates between two color values.
+ /// </summary>
+ /// <param name="from">The color value that represents 0 on the lerp number line.</param>
+ /// <param name="to">The color value that represents 1 on the lerp number line.</param>
+ /// <param name="frac">A value in the range [0, 1].</param>
+ /// <remarks>
+ /// This method does a simple lerp on each color value and on the alpha channel. It does
+ /// not properly take into account the alpha channel's effect on color blending.
+ /// </remarks>
+ public static ColorBgra Lerp(ColorBgra from, ColorBgra to, float frac)
+ {
+ ColorBgra ret = new ColorBgra();
+
+ ret.B = (byte)ClampToByte(Lerp(from.B, to.B, frac));
+ ret.G = (byte)ClampToByte(Lerp(from.G, to.G, frac));
+ ret.R = (byte)ClampToByte(Lerp(from.R, to.R, frac));
+ ret.A = (byte)ClampToByte(Lerp(from.A, to.A, frac));
+
+ return ret;
+ }
+ public static float Lerp(float from, float to, float frac)
+ {
+ return (from + frac * (to - from));
+ }
+
+ public static double Lerp(double from, double to, double frac)
+ {
+ return (from + frac * (to - from));
+ }
+ /// <summary>
+ /// Linearly interpolates between two color values.
+ /// </summary>
+ /// <param name="from">The color value that represents 0 on the lerp number line.</param>
+ /// <param name="to">The color value that represents 1 on the lerp number line.</param>
+ /// <param name="frac">A value in the range [0, 1].</param>
+ /// <remarks>
+ /// This method does a simple lerp on each color value and on the alpha channel. It does
+ /// not properly take into account the alpha channel's effect on color blending.
+ /// </remarks>
+ public static ColorBgra Lerp(ColorBgra from, ColorBgra to, double frac)
+ {
+ ColorBgra ret = new ColorBgra();
+
+ ret.B = (byte)ClampToByte(Lerp(from.B, to.B, frac));
+ ret.G = (byte)ClampToByte(Lerp(from.G, to.G, frac));
+ ret.R = (byte)ClampToByte(Lerp(from.R, to.R, frac));
+ ret.A = (byte)ClampToByte(Lerp(from.A, to.A, frac));
+
+ return ret;
+ }
+ public static byte ClampToByte(double x)
+ {
+ if (x > 255)
+ {
+ return 255;
+ }
+ else if (x < 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return (byte)x;
+ }
+ }
+ /// <summary>
+ /// Blends four colors together based on the given weight values.
+ /// </summary>
+ /// <returns>The blended color.</returns>
+ /// <remarks>
+ /// The weights should be 16-bit fixed point numbers that add up to 65536 ("1.0").
+ /// 4W16IP means "4 colors, weights, 16-bit integer precision"
+ /// </remarks>
+ public static ColorBgra BlendColors4W16IP(ColorBgra c1, uint w1, ColorBgra c2, uint w2, ColorBgra c3, uint w3, ColorBgra c4, uint w4)
+ {
+#if DEBUG
+ if ((w1 + w2 + w3 + w4) != 65536)
+ {
+ throw new ArgumentOutOfRangeException("w1 + w2 + w3 + w4 must equal 65536!");
+ }
+#endif
+
+ const uint ww = 32768;
+ uint af = (c1.A * w1) + (c2.A * w2) + (c3.A * w3) + (c4.A * w4);
+ uint a = (af + ww) >> 16;
+
+ uint b;
+ uint g;
+ uint r;
+
+ if (a == 0)
+ {
+ b = 0;
+ g = 0;
+ r = 0;
+ }
+ else
+ {
+ b = (uint)((((long)c1.A * c1.B * w1) + ((long)c2.A * c2.B * w2) + ((long)c3.A * c3.B * w3) + ((long)c4.A * c4.B * w4)) / af);
+ g = (uint)((((long)c1.A * c1.G * w1) + ((long)c2.A * c2.G * w2) + ((long)c3.A * c3.G * w3) + ((long)c4.A * c4.G * w4)) / af);
+ r = (uint)((((long)c1.A * c1.R * w1) + ((long)c2.A * c2.R * w2) + ((long)c3.A * c3.R * w3) + ((long)c4.A * c4.R * w4)) / af);
+ }
+
+ return ColorBgra.FromBgra((byte)b, (byte)g, (byte)r, (byte)a);
+ }
+
+ /// <summary>
+ /// Blends the colors based on the given weight values.
+ /// </summary>
+ /// <param name="c">The array of color values.</param>
+ /// <param name="w">The array of weight values.</param>
+ /// <returns>
+ /// The weights should be fixed point numbers.
+ /// The total summation of the weight values will be treated as "1.0".
+ /// Each color will be blended in proportionally to its weight value respective to
+ /// the total summation of the weight values.
+ /// </returns>
+ /// <remarks>
+ /// "WAIP" stands for "weights, arbitrary integer precision"</remarks>
+ public static ColorBgra BlendColorsWAIP(ColorBgra[] c, uint[] w)
+ {
+ if (c.Length != w.Length)
+ {
+ throw new ArgumentException("c.Length != w.Length");
+ }
+
+ if (c.Length == 0)
+ {
+ return ColorBgra.FromUInt32(0);
+ }
+
+ long wsum = 0;
+ long asum = 0;
+
+ for (int i = 0; i < w.Length; ++i)
+ {
+ wsum += w[i];
+ asum += c[i].A * w[i];
+ }
+
+ uint a = (uint)((asum + (wsum >> 1)) / wsum);
+
+ long b;
+ long g;
+ long r;
+
+ if (a == 0)
+ {
+ b = 0;
+ g = 0;
+ r = 0;
+ }
+ else
+ {
+ b = 0;
+ g = 0;
+ r = 0;
+
+ for (int i = 0; i < c.Length; ++i)
+ {
+ b += (long)c[i].A * c[i].B * w[i];
+ g += (long)c[i].A * c[i].G * w[i];
+ r += (long)c[i].A * c[i].R * w[i];
+ }
+
+ b /= asum;
+ g /= asum;
+ r /= asum;
+ }
+
+ return ColorBgra.FromUInt32((uint)b + ((uint)g << 8) + ((uint)r << 16) + ((uint)a << 24));
+ }
+
+ /// <summary>
+ /// Blends the colors based on the given weight values.
+ /// </summary>
+ /// <param name="c">The array of color values.</param>
+ /// <param name="w">The array of weight values.</param>
+ /// <returns>
+ /// Each color will be blended in proportionally to its weight value respective to
+ /// the total summation of the weight values.
+ /// </returns>
+ /// <remarks>
+ /// "WAIP" stands for "weights, floating-point"</remarks>
+ public static ColorBgra BlendColorsWFP(ColorBgra[] c, double[] w)
+ {
+ if (c.Length != w.Length)
+ {
+ throw new ArgumentException("c.Length != w.Length");
+ }
+
+ if (c.Length == 0)
+ {
+ return ColorBgra.FromUInt32(0);
+ }
+
+ double wsum = 0;
+ double asum = 0;
+
+ for (int i = 0; i < w.Length; ++i)
+ {
+ wsum += w[i];
+ asum += (double)c[i].A * w[i];
+ }
+
+ double a = asum / wsum;
+ double aMultWsum = a * wsum;
+
+ double b;
+ double g;
+ double r;
+
+ if (asum == 0)
+ {
+ b = 0;
+ g = 0;
+ r = 0;
+ }
+ else
+ {
+ b = 0;
+ g = 0;
+ r = 0;
+
+ for (int i = 0; i < c.Length; ++i)
+ {
+ b += (double)c[i].A * c[i].B * w[i];
+ g += (double)c[i].A * c[i].G * w[i];
+ r += (double)c[i].A * c[i].R * w[i];
+ }
+
+ b /= aMultWsum;
+ g /= aMultWsum;
+ r /= aMultWsum;
+ }
+
+ return ColorBgra.FromBgra((byte)b, (byte)g, (byte)r, (byte)a);
+ }
+
+ public override string ToString()
+ {
+ return "B: " + B + ", G: " + G + ", R: " + R + ", A: " + A;
+ }
+
+ /// <summary>
+ /// Casts a ColorBgra to a UInt32.
+ /// </summary>
+ public static explicit operator UInt32(ColorBgra color)
+ {
+ return color.Bgra;
+ }
+
+ /// <summary>
+ /// Casts a UInt32 to a ColorBgra.
+ /// </summary>
+ public static explicit operator ColorBgra(UInt32 uint32)
+ {
+ return ColorBgra.FromUInt32(uint32);
+ }
+
+ // Colors: copied from System.Drawing.Color's list (don't worry I didn't type it in
+ // manually, I used a code generator w/ reflection ...)
+
+ public static ColorBgra Transparent
+ {
+ get
+ {
+ return ColorBgra.FromBgra(255, 255, 255, 0);
+ }
+ }
+
+ public static ColorBgra AliceBlue
+ {
+ get
+ {
+ return ColorBgra.FromBgra(255, 248, 240, 255);
+ }
+ }
+
+ public static ColorBgra AntiqueWhite
+ {
+ get
+ {
+ return ColorBgra.FromBgra(215, 235, 250, 255);
+ }
+ }
+
+ public static ColorBgra Aqua
+ {
+ get
+ {
+ return ColorBgra.FromBgra(255, 255, 0, 255);
+ }
+ }
+
+ public static ColorBgra Aquamarine
+ {
+ get
+ {
+ return ColorBgra.FromBgra(212, 255, 127, 255);
+ }
+ }
+
+ public static ColorBgra Azure
+ {
+ get
+ {
+ return ColorBgra.FromBgra(255, 255, 240, 255);
+ }
+ }
+
+ public static ColorBgra Beige
+ {
+ get
+ {
+ return ColorBgra.FromBgra(220, 245, 245, 255);
+ }
+ }
+
+ public static ColorBgra Bisque
+ {
+ get
+ {
+ return ColorBgra.FromBgra(196, 228, 255, 255);
+ }
+ }
+
+ public static ColorBgra Black
+ {
+ get
+ {
+ return ColorBgra.FromBgra(0, 0, 0, 255);
+ }
+ }
+
+ public static ColorBgra BlanchedAlmond
+ {
+ get
+ {
+ return ColorBgra.FromBgra(205, 235, 255, 255);
+ }
+ }
+
+ public static ColorBgra Blue
+ {
+ get
+ {
+ return ColorBgra.FromBgra(255, 0, 0, 255);
+ }
+ }
+
+ public static ColorBgra BlueViolet
+ {
+ get
+ {
+ return ColorBgra.FromBgra(226, 43, 138, 255);
+ }
+ }
+
+ public static ColorBgra Brown
+ {
+ get
+ {
+ return ColorBgra.FromBgra(42, 42, 165, 255);
+ }
+ }
+
+ public static ColorBgra BurlyWood
+ {
+ get
+ {
+ return ColorBgra.FromBgra(135, 184, 222, 255);
+ }
+ }
+
+ public static ColorBgra CadetBlue
+ {
+ get
+ {
+ return ColorBgra.FromBgra(160, 158, 95, 255);
+ }
+ }
+
+ public static ColorBgra Chartreuse
+ {
+ get
+ {
+ return ColorBgra.FromBgra(0, 255, 127, 255);
+ }
+ }
+
+ public static ColorBgra Chocolate
+ {
+ get
+ {
+ return ColorBgra.FromBgra(30, 105, 210, 255);
+ }
+ }
+
+ public static ColorBgra Coral
+ {
+ get
+ {
+ return ColorBgra.FromBgra(80, 127, 255, 255);
+ }
+ }
+
+ public static ColorBgra CornflowerBlue
+ {
+ get
+ {
+ return ColorBgra.FromBgra(237, 149, 100, 255);
+ }
+ }
+
+ public static ColorBgra Cornsilk
+ {
+ get
+ {
+ return ColorBgra.FromBgra(220, 248, 255, 255);
+ }
+ }
+
+ public static ColorBgra Crimson
+ {
+ get
+ {
+ return ColorBgra.FromBgra(60, 20, 220, 255);
+ }
+ }
+
+ public static ColorBgra Cyan
+ {
+ get
+ {
+ return ColorBgra.FromBgra(255, 255, 0, 255);
+ }
+ }
+
+ public static ColorBgra DarkBlue
+ {
+ get
+ {
+ return ColorBgra.FromBgra(139, 0, 0, 255);
+ }
+ }
+
+ public static ColorBgra DarkCyan
+ {
+ get
+ {
+ return ColorBgra.FromBgra(139, 139, 0, 255);
+ }
+ }
+
+ public static ColorBgra DarkGoldenrod
+ {
+ get
+ {
+ return ColorBgra.FromBgra(11, 134, 184, 255);
+ }
+ }
+
+ public static ColorBgra DarkGray
+ {
+ get
+ {
+ return ColorBgra.FromBgra(169, 169, 169, 255);
+ }
+ }
+
+ public static ColorBgra DarkGreen
+ {
+ get
+ {
+ return ColorBgra.FromBgra(0, 100, 0, 255);
+ }
+ }
+
+ public static ColorBgra DarkKhaki
+ {
+ get
+ {
+ return ColorBgra.FromBgra(107, 183, 189, 255);
+ }
+ }
+
+ public static ColorBgra DarkMagenta
+ {
+ get
+ {
+ return ColorBgra.FromBgra(139, 0, 139, 255);
+ }
+ }
+
+ public static ColorBgra DarkOliveGreen
+ {
+ get
+ {
+ return ColorBgra.FromBgra(47, 107, 85, 255);
+ }
+ }
+
+ public static ColorBgra DarkOrange
+ {
+ get
+ {
+ return ColorBgra.FromBgra(0, 140, 255, 255);
+ }
+ }
+
+ public static ColorBgra DarkOrchid
+ {
+ get
+ {
+ return ColorBgra.FromBgra(204, 50, 153, 255);
+ }
+ }
+