summaryrefslogtreecommitdiff
path: root/src/plugins/TransitionsInterfaces.vala
blob: a079146fb8648398804062ff6b63fac6a4d444d0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
/* Copyright 2016 Software Freedom Conservancy Inc.
 *
 * This software is licensed under the GNU Lesser General Public License
 * (version 2.1 or later).  See the COPYING file in this distribution.
 */

/**
 * Transitions are used in Shotwell for interstitial effects in slideshow mode. They may
 * also be used elsewhere in future releases.
 *
 * Plugin writers should start by implementing a {@link Descriptor} which in turn Shotwell uses
 * to instantiate an {@link Effect}.
 */
namespace Spit.Transitions {

/**
 * The current version of the Transitions plugin interface.
 */
public const int CURRENT_INTERFACE = 0;

/**
 * Direction indicates what direction (animated motion) the {@link Effect} should simulate the 
 * images are moving, if appropriate.
 * 
 * The direction indicates from what side or corner of the screen the new image should come in from.
 * Thus, a LEFT slide means the current image exits via the left-hand edge of the screen and the 
 * new image moves into place from the right-hand edge.
 *
 * UP, DOWN, and diagonals may be added at some point.
 */
public enum Direction {
    LEFT = 0,
    RIGHT = 1,
    
    /**
     * Convenience definition (for LTR readers).
     */
    FORWARD = LEFT,
    
    /**
     * Convenience definition (for LTR readers).
     */
    BACKWARD = RIGHT
}

/**
 * Visuals contains the pertinent drawing information for the transition that must occur.
 * 
 * A Visuals object is supplied to {@link Effect} at the start of the transition and during each 
 * call to paint to the screen.
 *
 * Note that if starting with a blank screen, from_pixbuf will be null and from_pos will be
 * zeroed. The transition should be considered to start from a blank screen of the supplied
 * background color.
 *
 * Also note that if transitioning to a blank screen, to_pixbuf will be null and to_pos will be
 * zeroed. Like the prior case, the transition should move toward a blank screen of the background
 * color.
 */
public class Visuals : Object {
    /**
     * Returns the starting pixbuf (the pixbuf currently on the display).
     *
     * If transitioning from a blank screen, this will return null.
     */
    public Gdk.Pixbuf? from_pixbuf { get; private set; }
    
    /**
     * Returns the position of the starting pixbuf on the display.
     *
     * If transitioning from a blank screen, this will be zeroed.
     */
    public Gdk.Rectangle from_pos { get; private set; }
    
    /**
     * Returns the ending pixbuf (the pixbuf that the transition should result in).
     *
     * If transitioning to a blank screen, this will return null.
     */
    public Gdk.Pixbuf? to_pixbuf { get; private set; }
    
    /**
     * Returns the position of the ending pixbuf on the display.
     *
     * If transitioning to a blank screen, this will be zeroed.
     */
    public Gdk.Rectangle to_pos { get; private set; }
    
    /**
     * Returns the background color of the viewport.
     */
    public Gdk.RGBA bg_color { get; private set; }
    
    public Visuals(Gdk.Pixbuf? from_pixbuf, Gdk.Rectangle from_pos, Gdk.Pixbuf? to_pixbuf,
        Gdk.Rectangle to_pos, Gdk.RGBA bg_color) {
        this.from_pixbuf = from_pixbuf;
        this.from_pos = from_pos;
        this.to_pixbuf = to_pixbuf;
        this.to_pos = to_pos;
        this.bg_color = bg_color;
    }
    
    //
    // For future expansion.
    //
    protected virtual void reserved0() {}
    protected virtual void reserved1() {}
    protected virtual void reserved2() {}
    protected virtual void reserved3() {}
    protected virtual void reserved4() {}
    protected virtual void reserved5() {}
    protected virtual void reserved6() {}
    protected virtual void reserved7() {}
}

/**
 * Motion contains all the pertinent information regarding the animation of the transition.
 *
 * Some of Motion's information may not apply to a transition effect (such as Direction for a 
 * fade effect).
 */
public class Motion : Object {
    /**
     * Returns the direction the transition should occur in (if pertinent to the {@link Effect}.
     */
    public Direction direction { get; private set; }
    
    /**
     * Returns the frames per second of the {@link Effect}.
     */
    public int fps { get; private set; }
    
    /**
     * Returns the amount of time the transition should take (in milliseconds).
     */
    public int duration_msec { get; private set; }
    
    /**
     * Returns the number of frames that should be required to perform the transition in the
     * expected {@link duration_msec}.
     */
    public int total_frames { 
        get {
            return (int) ((double) fps * ((double) duration_msec / 1000.0));
        }
    }
    
    /**
     * Returns the approximate time between each frame draw (in milliseconds).
     */
    public int tick_msec {
        get {
            return (int) (1000.0 / (double) fps);
        }
    }
    
    public Motion(Direction direction, int fps, int duration_msec) {
        this.direction = direction;
        this.fps = fps;
        this.duration_msec = duration_msec;
    }
    
    /**
     * Returns a value from 0.0 to 1.0 that represents the percentage of the transition's completion
     * for the specified frame.
     */
    public double get_alpha(int frame_number) {
        return (double) frame_number / (double) total_frames;
    }
    
    //
    // For future expansion.
    //
    protected virtual void reserved0() {}
    protected virtual void reserved1() {}
    protected virtual void reserved2() {}
    protected virtual void reserved3() {}
    protected virtual void reserved4() {}
    protected virtual void reserved5() {}
    protected virtual void reserved6() {}
    protected virtual void reserved7() {}
}

/**
 * A Descriptor offers a factory method for creating {@link Effect} instances.
 */
public interface Descriptor : Object, Spit.Pluggable {
    /**
     * Returns an instance of the {@link Effect} this descriptor represents.
     */
    public abstract Effect create(Spit.HostInterface host);
    
    //
    // For future expansion.
    //
    protected virtual void reserved0() {}
    protected virtual void reserved1() {}
    protected virtual void reserved2() {}
    protected virtual void reserved3() {}
    protected virtual void reserved4() {}
    protected virtual void reserved5() {}
    protected virtual void reserved6() {}
    protected virtual void reserved7() {}
}

/**
 * An Effect represents an interstitial effect that is used to transition the display from one 
 * image to another.
 * 
 * An Effect must hold state so that it knows what it should be drawn at any call to {@link paint}
 * (which is called regularly during a transition). That is, it should be able to draw any frame of
 * the transition at any time. The same frame may need to be drawn multiple times, or the host
 * may skip ahead and ask for a frame well ahead of the last requested one.
 *
 * ''Frame numbers are one-based throughout this interface''. This is because the initial state (the
 * blank viewport or the starting pixbuf) is frame zero. The Effect is never called to paint this
 * frame.  The Effect is also not called to paint the final frame (a blank viewport or the ending
 * pixbuf).
 *
 * If the Effect uses background threads for its work, it should use the appropriate primitives
 * for critical sections. All calls to this interface will be from the context of the main UI
 * thread. ''None of these calls should block.''
 *
 * If the Details object needs to be held by the Effect, its reference to it should be dropped at
 * the end of the cycle (or shortly thereafter).
 *
 * An instance may be reused and should be prepared for restarts.
 */
public interface Effect : Object {
    /**
     * Returns frames per second (FPS) information for this effect.
     *
     * If the min_fps is not met, the Effect may be cancelled or the host will skip ahead.
     *
     * @param desired_fps The desired FPS of the transition.  Return zero if no
     *        transition is to occur (instantaneous or null transition).
     * @param min_fps The minimum FPS before the effect is consider "ruined".
     *        Return zero if any FPS is acceptable.
     */
    public abstract void get_fps(out int desired_fps, out int min_fps);
    
    /**
     * Called when the effect is starting.
     * 
     * All state should be reset. The frame number, which is not supplied, is one.
     */
    public abstract void start(Visuals visuals, Motion motion);
    
    /**
     * Return true if the Effect needs the background cleared prior to calling {@link paint}.
     */
    public abstract bool needs_clear_background();
    
    /**
     * Called when the effect needs to paint (i.e. an expose or draw event has occurred).
     * 
     * This call should ''not'' advance the state of the effect (i.e. it may be called more than 
     * once for the same frame).
     *
     * @param ctx The Cairo context the Effect should use to paint the transition.
     * @param width The width (in pixels) of the Cairo surface.
     * @param height The height (in pixels) of the Cairo surface.
     * @param frame_number The ''one-based'' frame being drawn.
     */
    public abstract void paint(Visuals visuals, Motion motion, Cairo.Context ctx, int width,
        int height, int frame_number);
    
    /**
     * Called to notify the effect that the state of the transition should advance to the specified
     * frame number.
     * 
     * Note: There is no guarantee frame numbers will be consecutive between calls
     * to next, especially if the transition clock is attempting to catch up.
     *
     * @param frame_number The ''one-based'' frame being advanced to.
     */
    public abstract void advance(Visuals visuals, Motion motion, int frame_number);
    
    /**
     * Called if the Effect should halt the transition.
     * 
     * It only needs to reset state if {@link start} is called again.
     */
    public abstract void cancel();
    
    //
    // For future expansion.
    //
    protected virtual void reserved0() {}
    protected virtual void reserved1() {}
    protected virtual void reserved2() {}
    protected virtual void reserved3() {}
    protected virtual void reserved4() {}
    protected virtual void reserved5() {}
    protected virtual void reserved6() {}
    protected virtual void reserved7() {}
}

}