36
36
public abstract class BounceFadePopupWindow : Gtk.Window
40
38
Stage<BounceFadePopupWindow> stage = new Stage<BounceFadePopupWindow> ();
41
39
Gdk.Pixbuf textImage = null;
46
public BounceFadePopupWindow (TextEditor editor, Rectangle bounds) : base (Gtk.WindowType.Popup)
42
protected double scale = 0.0;
43
protected double opacity = 1.0;
45
public BounceFadePopupWindow (TextEditor editor) : base (Gtk.WindowType.Popup)
48
this.Decorated = false;
48
throw new InvalidOperationException ("Only works with composited screen. Check Widget.IsComposited.");
49
DoubleBuffered = true;
51
53
this.editor = editor;
54
Events = Gdk.EventMask.ExposureMask;
56
58
BounceEasing = Easing.Sine;
60
var rgbaColormap = Screen.RgbaColormap;
61
if (rgbaColormap == null)
63
Colormap = rgbaColormap;
65
stage.ActorStep += OnAnimationActorStep;
66
stage.Iteration += OnAnimationIteration;
67
stage.UpdateFrequency = 10;
70
protected TextEditor Editor { get { return editor; } }
59
72
/// <summary>Duration of the animation, in milliseconds.</summary>
60
73
public uint Duration { get; set; }
68
81
/// <summary>The easing used for the bounce part of the animation.</summary>
69
82
public Easing BounceEasing { get; set; }
85
protected int width, height;
86
double vValue, hValue;
87
protected Rectangle bounds;
89
public virtual void Popup ()
74
throw new InvalidOperationException ("Only works with composited screen. Check Widget.IsComposited.");
76
var rgbaColormap = Screen.RgbaColormap;
77
if (rgbaColormap == null)
79
Colormap = rgbaColormap;
82
91
editor.GdkWindow.GetOrigin (out x, out y);
83
Move (x + bounds.X - (int)(ExpandWidth / 2), y + bounds.Y - (int)(ExpandHeight / 2));
84
Resize (bounds.Width + (int)ExpandWidth, bounds.Height + (int)ExpandHeight);
86
stage.ActorStep += OnAnimationActorStep;
87
stage.Iteration += OnAnimationIteration;
89
stage.UpdateFrequency = 10;
90
stage.Add (this, Duration);
92
bounds = CalculateInitialBounds ();
93
x = x + bounds.X - (int)(ExpandWidth / 2);
94
y = y + bounds.Y - (int)(ExpandHeight / 2);
97
width = bounds.Width + (int)ExpandWidth;
98
height = bounds.Height + (int)ExpandHeight;
99
Resize (width, height);
102
stage.AddOrReset (this, Duration);
108
protected void ListenToEvents ()
110
editor.VAdjustment.ValueChanged += HandleEditorVAdjustmentValueChanged;
111
editor.HAdjustment.ValueChanged += HandleEditorHAdjustmentValueChanged;
112
vValue = editor.VAdjustment.Value;
113
hValue = editor.HAdjustment.Value;
116
protected override void OnShown ()
121
protected void DetachEvents ()
123
editor.VAdjustment.ValueChanged -= HandleEditorVAdjustmentValueChanged;
124
editor.HAdjustment.ValueChanged -= HandleEditorHAdjustmentValueChanged;
127
protected override void OnHidden ()
133
void HandleEditorVAdjustmentValueChanged (object sender, EventArgs e)
135
y += (int)(vValue - editor.VAdjustment.Value);
137
vValue = editor.VAdjustment.Value;
140
void HandleEditorHAdjustmentValueChanged (object sender, EventArgs e)
142
x += (int)(hValue - editor.HAdjustment.Value);
144
hValue = editor.HAdjustment.Value;
96
147
void OnAnimationIteration (object sender, EventArgs args)
101
bool OnAnimationActorStep (Actor<BounceFadePopupWindow> actor)
152
protected virtual bool OnAnimationActorStep (Actor<BounceFadePopupWindow> actor)
103
154
if (actor.Expired) {
155
OnAnimationCompleted ();
113
164
//for the second half, vary opacity linearly from 1 to 0.
115
scale = scale = Choreographer.Compose (1.0, BounceEasing);
166
scale = Choreographer.Compose (1.0, BounceEasing);
116
167
opacity = 2.0 - actor.Percent * 2;
172
protected virtual void OnAnimationCompleted ()
121
177
protected override void OnDestroyed ()
179
editor.VAdjustment.ValueChanged -= HandleEditorVAdjustmentValueChanged;
123
180
base.OnDestroyed ();
184
internal virtual void StopPlaying ()
124
186
stage.Playing = false;
126
188
if (textImage != null) {
128
190
textImage = null;
132
protected abstract Pixbuf RenderInitialPixbuf (Gdk.Window parentwindow, Rectangle bounds);
135
protected override bool OnExposeEvent (Gdk.EventExpose evnt)
138
using (var g = Gdk.CairoHelper.Create (evnt.Window)) {
139
g.SetSourceRGBA (1, 1, 1, 0);
140
g.Operator = Cairo.Operator.Source;
144
if (textImage == null) {
145
var img = RenderInitialPixbuf (evnt.Window, bounds);
147
textImage = img.AddAlpha (false, 0, 0, 0);
154
int i = (int)(ExpandWidth * scale);
155
int j = (int)(ExpandHeight * scale);
156
int winw = Allocation.Width, winh = Allocation.Height;
157
int scaledw = winw - (int)(ExpandWidth - i);
158
int scaledh = winh - (int)(ExpandHeight - j);
160
using (var scaled = textImage.ScaleSimple (scaledw, scaledh, Gdk.InterpType.Bilinear)) {
161
if (scaled != null) {
162
SetPixbufChannel (scaled, 4, (byte)(opacity*255));
163
using (var gc = new Gdk.GC (evnt.Window)) {
164
scaled.RenderToDrawable (evnt.Window, gc, 0, 0, (winw - scaledw) / 2, (winh - scaledh) / 2,
165
scaledw, scaledh, Gdk.RgbDither.None, 0, 0);
169
} catch (Exception e) {
170
Console.WriteLine ("Exception in animation:" + e);
176
/// Utility method for setting a single channel in a pixbuf.
178
/// <param name="channel">Channel indexx, 1-based.</param>
179
/// <param name="value">Value for all pixels in that channel.</param>
180
unsafe void SetPixbufChannel (Gdk.Pixbuf p, int channel, byte value)
182
int nChannels = p.NChannels;
184
if (channel > nChannels)
185
throw new ArgumentException ("channel");
187
byte *start = (byte*) p.Pixels;
188
int rowStride = p.Rowstride;
190
byte *lastRow = start + p.Rowstride * (p.Height - 1);
191
for (byte *row = start; row <= lastRow; row += rowStride) {
192
byte *colEnd = row + width * nChannels;
193
for (byte *col = row + channel - 1; col < colEnd; col += nChannels)
194
protected abstract Rectangle CalculateInitialBounds ();