5
// Mike KrĆ¼ger <mkrueger@xamarin.com>
7
// Copyright (c) 2011 Xamarin <http://xamarin.com>
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:
16
// The above copyright notice and this permission notice shall be included in
17
// all copies or substantial portions of the Software.
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
28
using System.ComponentModel;
32
using Mono.TextEditor;
33
using MonoDevelop.Components;
34
using MonoDevelop.Core;
36
using MonoDevelop.Projects;
37
using MonoDevelop.Ide.Projects;
38
using MonoDevelop.Ide;
39
using System.Collections.Generic;
42
namespace MonoDevelop.MacDev.PlistEditor
45
public class ImageChooser : Button
47
static Pixbuf WarningIcon = Pixbuf.LoadFromResource ("error.png");
49
Size imageSize, displaySize, acceptedSize, recommendedSize;
55
Gtk.TargetEntry[] targetEntryTypes = new Gtk.TargetEntry[] {
56
new Gtk.TargetEntry ("text/uri-list", 0, 100u)
60
public string Description {
61
get { return description; }
63
if (value == description)
72
public Size DisplaySize {
73
get { return displaySize; }
75
this.displaySize = value;
76
image.WidthRequest = value.Width;
77
image.HeightRequest = value.Height;
81
public Size AcceptedSize {
82
get { return acceptedSize; }
84
if (value == acceptedSize)
87
recommendedSize = value;
95
public Size RecommendedSize {
96
get { return recommendedSize; }
98
if (value == recommendedSize)
101
recommendedSize = value;
108
public List<string> SupportedFormats {
113
/// Project virtual path of the selected file.
115
public FilePath SelectedProjectFile { get; set; }
117
public void SetDisplayPixbuf (Pixbuf pixbuf)
119
DestroyScaledPixbuf ();
121
imageSize = pixbuf != null ? new Size (pixbuf.Width, pixbuf.Height) : Size.Empty;
123
//scale image down to fit
124
if (pixbuf != null && (pixbuf.Width > DisplaySize.Width || pixbuf.Height > DisplaySize.Height)) {
125
if (DisplaySize.Width == 0 || displaySize.Height == 0)
126
throw new NotSupportedException ("Display size not set.");
127
double aspect = pixbuf.Height / (double)pixbuf.Width;
128
int destWidth = Math.Min ((int) (DisplaySize.Height / aspect), pixbuf.Width);
129
destWidth = Math.Max (1, Math.Min (DisplaySize.Width, destWidth));
130
int destHeight = Math.Min ((int) (DisplaySize.Width * aspect), pixbuf.Height);
131
destHeight = Math.Max (1, Math.Min (DisplaySize.Height, destHeight));
132
scaledPixbuf = pixbuf = pixbuf.ScaleSimple (destWidth, destHeight, InterpType.Bilinear);
135
image.Pixbuf = pixbuf;
140
public ImageChooser ()
142
this.image = new Gtk.Image ();
143
this.Add (this.image);
146
Gtk.Drag.DestSet (this, DestDefaults.Drop, targetEntryTypes, DragAction.Link);
147
SupportedFormats = new List<string> { "png" };
150
void UpdateTooltip ()
152
if (imageSize != Size.Empty && RecommendedSize != Size.Empty && imageSize != RecommendedSize) {
153
string warning = GettextCatalog.GetString ("<b>WARNING:</b> The size of the current image does not match the recommended size of {0}x{1} pixels.",
154
RecommendedSize.Width, RecommendedSize.Height);
156
if (!string.IsNullOrEmpty (description))
157
TooltipMarkup = GLib.Markup.EscapeText (description) + "\n\n" + warning;
159
TooltipMarkup = warning;
160
} else if (RecommendedSize != Size.Empty) {
161
string suggestion = GettextCatalog.GetString ("The recommended size of this image is {0}x{1} pixels.", RecommendedSize.Width, RecommendedSize.Height);
163
if (!string.IsNullOrEmpty (description))
164
TooltipText = description + "\n\n" + suggestion;
166
TooltipText = suggestion;
167
} else if (string.IsNullOrEmpty (description)) {
168
TooltipText = GettextCatalog.GetString ("Choose an image.");
170
TooltipText = description;
174
public bool CheckImage (FilePath path)
177
string errorTitle = null;
178
string errorMessage = null;
180
using (var type = Pixbuf.GetFileInfo (path, out width, out height)) {
182
errorTitle = GettextCatalog.GetString ("Invalid file selected");
183
errorMessage = GettextCatalog.GetString ("Selected file was not a valid image.");
184
} else if (type.IsDisabled) {
185
errorTitle = GettextCatalog.GetString ("Unsupported image selected");
186
errorMessage = GettextCatalog.GetString ("Support for loading images of type '{0}' has not been enabled.", type.Name);
187
} else if (AcceptedSize != Size.Empty && AcceptedSize != new Size (width, height)) {
188
errorTitle = GettextCatalog.GetString ("Incorrect image dimensions");
189
errorMessage = GettextCatalog.GetString (
190
"Only images with size {0}x{1} are allowed. Picture was {2}x{3}.",
191
AcceptedSize.Width, AcceptedSize.Height, width, height);
192
} else if (!SupportedFormats.Contains (type.Name)) {
193
var formats = string.Join (", ", SupportedFormats.Select (f => "'" + f + "'"));
194
errorTitle = GettextCatalog.GetString ("Invalid image selected");
195
errorMessage = GettextCatalog.GetString ("An image of type '{0}' has been selected but you must select an image of type '{1}'.", type.Name, formats);
200
LoggingService.LogError ("{0}: {1}", errorTitle, errorMessage);
201
MessageService.ShowError (errorTitle, errorMessage);
206
protected override void OnClicked ()
212
var formats = string.Join ("|", SupportedFormats.Select (f => "*." + f));
213
var dialog = new ProjectFileSelectorDialog (project, "All Images", formats);
216
if (AcceptedSize.IsEmpty)
217
dialog.Title = GettextCatalog.GetString ("Select image...");
219
dialog.Title = GettextCatalog.GetString ("Select image ({0}x{1})...", RecommendedSize.Width, RecommendedSize.Height);
220
while (MessageService.RunCustomDialog (dialog) == (int)Gtk.ResponseType.Ok && dialog.SelectedFile != null) {
221
var path = dialog.SelectedFile.FilePath;
222
if (!CheckImage (path))
225
SelectedProjectFile = dialog.SelectedFile.ProjectVirtualPath;
226
OnChanged (EventArgs.Empty);
234
public void SetProject (Project proj)
239
protected override void OnDestroyed ()
242
DestroyScaledPixbuf ();
245
protected override void OnRealized ()
248
if (displaySize.Width <= 0 || displaySize.Height <= 0)
249
throw new InvalidOperationException ("Display size not set.");
252
protected override bool OnExposeEvent (EventExpose evnt)
254
var ret = base.OnExposeEvent (evnt);
256
if (image.Pixbuf == null) {
257
using (var cr = CairoHelper.Create (evnt.Window)) {
258
cr.Rectangle (evnt.Region.Clipbox.X, evnt.Region.Clipbox.Y, evnt.Region.Clipbox.Width, evnt.Region.Clipbox.Height);
261
var imgAlloc = image.Allocation;
262
cr.Translate (imgAlloc.X, imgAlloc.Y);
264
using (var layout = new Pango.Layout (PangoContext)) {
265
layout.SetText (string.Format ("({0}x{1})", RecommendedSize.Width, RecommendedSize.Height));
266
layout.Width = (int) (imgAlloc.Width * Pango.Scale.PangoScale);
267
layout.Wrap = Pango.WrapMode.WordChar;
268
layout.Alignment = Pango.Alignment.Center;
271
layout.GetPixelSize (out pw, out ph);
272
cr.MoveTo (0, (imgAlloc.Height - ph) / 2);
273
cr.Color = new Cairo.Color (0.5, 0.5, 0.5);
274
cr.ShowLayout (layout);
277
CairoExtensions.RoundedRectangle (cr, 5, 5, imgAlloc.Width - 10, imgAlloc.Height - 10, 5);
279
cr.Color = new Cairo.Color (0.8, 0.8, 0.8);
280
cr.SetDash (new double[] { 12, 2 }, 0);
283
} else if (RecommendedSize != Size.Empty && imageSize != RecommendedSize) {
284
using (var cr = CairoHelper.Create (evnt.Window)) {
285
cr.Rectangle (evnt.Region.Clipbox.X, evnt.Region.Clipbox.Y, evnt.Region.Clipbox.Width, evnt.Region.Clipbox.Height);
288
var imgAlloc = image.Allocation;
289
cr.Translate (imgAlloc.X + displaySize.Width - WarningIcon.Width - 3, imgAlloc.Y + displaySize.Height - WarningIcon.Height);
291
CairoHelper.SetSourcePixbuf (cr, WarningIcon, 0, 0);
292
cr.Rectangle (0, 0, WarningIcon.Width, WarningIcon.Height);
300
protected virtual void OnChanged (System.EventArgs e)
302
EventHandler handler = this.Changed;
307
public event EventHandler Changed;
309
void DestroyScaledPixbuf ()
311
if (scaledPixbuf != null) {
312
scaledPixbuf.Dispose ();
317
protected override void OnDragDataReceived (DragContext context, int x, int y, SelectionData selection_data, uint info, uint time_)
319
base.OnDragDataReceived (context, x, y, selection_data, info, time_);
321
string fullData = System.Text.Encoding.UTF8.GetString (selection_data.Data);
323
foreach (string individualFile in fullData.Split ('\n')) {
324
string file = individualFile.Trim ();
325
if (file.StartsWith ("file://")) {
326
file = new Uri(file).LocalPath;
327
if (!CheckImage (file))
330
file = project.GetRelativeChildPath (file);
331
SelectedProjectFile = file;
332
OnChanged (EventArgs.Empty);
b'\\ No newline at end of file'