1 //
2 // GdkExtensions.cs
3 //
4 // Author:
5 //       Jonathan Pobst <monkey@jpobst.com>
6 //
7 // Copyright (c) 2010 Jonathan Pobst
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
15 //
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
18 //
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 // THE SOFTWARE.
26 
27 using System;
28 using Gdk;
29 
30 namespace Pinta.Core
31 {
32 	public static class GdkExtensions
33 	{
34 		// Invalidate the whole thing
Invalidate(this Window w)35 		public static void Invalidate (this Window w)
36 		{
37 			int width;
38 			int height;
39 
40 			w.GetSize (out width, out height);
41 
42 			w.InvalidateRect (new Rectangle (0, 0, width, height), true);
43 		}
44 
GetBounds(this Window w)45 		public static Rectangle GetBounds (this Window w)
46 		{
47 			int width;
48 			int height;
49 
50 			w.GetSize (out width, out height);
51 
52 			return new Rectangle (0, 0, width, height);
53 		}
54 
GetSize(this Window w)55 		public static Size GetSize (this Window w)
56 		{
57 			int width;
58 			int height;
59 
60 			w.GetSize (out width, out height);
61 
62 			return new Size (width, height);
63 		}
64 
ToCairoColor(this Gdk.Color color)65 		public static Cairo.Color ToCairoColor (this Gdk.Color color)
66 		{
67 			return new Cairo.Color ((double)color.Red / ushort.MaxValue, (double)color.Green / ushort.MaxValue, (double)color.Blue / ushort.MaxValue);
68 		}
69 
GetCairoColor(this Gtk.ColorSelection selection)70 		public static Cairo.Color GetCairoColor (this Gtk.ColorSelection selection)
71 		{
72 			Cairo.Color cairo_color = selection.CurrentColor.ToCairoColor ();
73 			return new Cairo.Color (cairo_color.R, cairo_color.G, cairo_color.B, (double)selection.CurrentAlpha / ushort.MaxValue);
74 		}
75 
Center(this Gdk.Rectangle rect)76 		public static Gdk.Point Center (this Gdk.Rectangle rect)
77 		{
78 			return new Gdk.Point(rect.X + rect.Width / 2, rect.Y + rect.Height / 2);
79 		}
80 
ToBgraColor(this Gdk.Color color)81 		public static ColorBgra ToBgraColor (this Gdk.Color color)
82 		{
83 			return ColorBgra.FromBgr ((byte)(color.Blue * 255 / ushort.MaxValue),  (byte)(color.Green * 255 / ushort.MaxValue), (byte)(color.Red * 255 / ushort.MaxValue));
84 		}
85 
IsNotSet(this Point p)86 		public static bool IsNotSet (this Point p)
87 		{
88 			return p.X == int.MinValue && p.Y == int.MinValue;
89 		}
90 
IsShiftPressed(this ModifierType m)91         public static bool IsShiftPressed (this ModifierType m)
92         {
93             return (m & ModifierType.ShiftMask) == ModifierType.ShiftMask;
94         }
95 
IsControlPressed(this ModifierType m)96 		public static bool IsControlPressed (this ModifierType m)
97 		{
98 			return (m & ModifierType.ControlMask) == ModifierType.ControlMask;
99 		}
100 
IsAltPressed(this ModifierType m)101 		public static bool IsAltPressed (this ModifierType m)
102 		{
103 			return (m & ModifierType.Mod1Mask) == ModifierType.Mod1Mask;
104 		}
105 
IsShiftPressed(this EventButton ev)106 		public static bool IsShiftPressed (this EventButton ev)
107 		{
108             return ev.State.IsShiftPressed ();
109 		}
110 
IsControlPressed(this EventButton ev)111 		public static bool IsControlPressed (this EventButton ev)
112 		{
113             return ev.State.IsControlPressed ();
114 		}
115 
IsAltPressed(this EventButton ev)116 		public static bool IsAltPressed (this EventButton ev)
117 		{
118 			return ev.State.IsAltPressed ();
119 		}
120 
121 		/// <summary>
122 		/// Filters out all modifier keys except Ctrl/Shift/Alt. This prevents Caps Lock, Num Lock, etc
123 		/// from appearing as active modifier keys.
124 		/// </summary>
FilterModifierKeys(this ModifierType current_state)125 		public static ModifierType FilterModifierKeys (this ModifierType current_state)
126         {
127             var state = Gdk.ModifierType.None;
128 
129 			state |= (current_state & Gdk.ModifierType.ControlMask);
130 			state |= (current_state & Gdk.ModifierType.ShiftMask);
131 			state |= (current_state & Gdk.ModifierType.Mod1Mask);
132 			state |= (current_state & Gdk.ModifierType.MetaMask); // Command key on macOS.
133 
134             return state;
135         }
136 
GetPoint(this EventButton ev)137 		public static Cairo.PointD GetPoint (this EventButton ev)
138 		{
139 			return new Cairo.PointD (ev.X, ev.Y);
140 		}
141 
142 		/// <summary>
143 		/// The implementation of Rectangle.Bottom was changed in 2.12.11 to fix an off-by-one error,
144 		/// and this function provides the newer behaviour for backwards compatibility with older versions.
145 		/// </summary>
GetBottom(this Rectangle r)146 		public static int GetBottom(this Rectangle r)
147 		{
148 			return r.Y + r.Height - 1;
149 		}
150 
151 		/// <summary>
152 		/// The implementation of Rectangle.Right was changed in 2.12.11 to fix an off-by-one error,
153 		/// and this function provides the newer behaviour for backwards compatibility with older versions.
154 		/// </summary>
GetRight(this Rectangle r)155 		public static int GetRight(this Rectangle r)
156 		{
157 			return r.X + r.Width - 1;
158 		}
159 
ToSurface(this Pixbuf pixbuf)160         public static Cairo.Surface ToSurface (this Pixbuf pixbuf)
161         {
162             var surface = CairoExtensions.CreateImageSurface (Cairo.Format.ARGB32, pixbuf.Width, pixbuf.Height);
163 
164 	    using (var g = new Cairo.Context (surface)) {
165                 Gdk.CairoHelper.SetSourcePixbuf (g, pixbuf, 0, 0);
166                 g.Paint ();
167             }
168 
169             return surface;
170         }
171 
CreateColorSwatch(int size, Color color)172         public static Pixbuf CreateColorSwatch (int size, Color color)
173         {
174             using (var pmap = new Pixmap (Screen.Default.RootWindow, size, size))
175             using (var gc = new Gdk.GC (pmap)) {
176                 gc.RgbFgColor = color;
177                 pmap.DrawRectangle (gc, true, 0, 0, size, size);
178 
179                 gc.RgbFgColor = new Color (0, 0, 0);
180                 pmap.DrawRectangle (gc, false, 0, 0, (size - 1), (size - 1));
181 
182                 return Pixbuf.FromDrawable (pmap, pmap.Colormap, 0, 0, 0, 0, size, size);
183             }
184         }
185 
CreateTransparentColorSwatch(bool drawBorder)186         public static Pixbuf CreateTransparentColorSwatch (bool drawBorder)
187         {
188             var size = 16;
189 
190             using (var pmap = new Pixmap (Screen.Default.RootWindow, size, size))
191             using (var gc = new Gdk.GC (pmap)) {
192                 gc.RgbFgColor = new Color (255, 255, 255);
193                 pmap.DrawRectangle (gc, true, 0, 0, size, size);
194 
195                 gc.RgbFgColor = new Color (200, 200, 200);
196                 pmap.DrawRectangle (gc, true, 0, 0, (size / 2), (size / 2));
197                 pmap.DrawRectangle (gc, true, size / 2, size / 2, (size / 2), (size / 2));
198 
199                 if (drawBorder) {
200                     gc.RgbFgColor = new Color (0, 0, 0);
201                     pmap.DrawRectangle (gc, false, 0, 0, (size - 1), (size - 1));
202                 }
203 
204                 return Pixbuf.FromDrawable (pmap, pmap.Colormap, 0, 0, 0, 0, size, size);
205             }
206         }
207     }
208 }
209