1 | package org.expeditee.gio;
|
---|
2 |
|
---|
3 | import java.util.Stack;
|
---|
4 |
|
---|
5 | import org.expeditee.core.Clip;
|
---|
6 | import org.expeditee.core.EnforcedClipStack;
|
---|
7 | import org.expeditee.core.Image;
|
---|
8 | import org.expeditee.core.EnforcedClipStack.EnforcedClipKey;
|
---|
9 |
|
---|
10 | /**
|
---|
11 | * Helper-class for the graphics manager to maintain a stack of drawing
|
---|
12 | * surfaces. Should be sub-typed by the platform-specific graphics manager
|
---|
13 | * to use the appropriate surface class.
|
---|
14 | */
|
---|
15 | public abstract class GraphicsSurfaceStack<T> {
|
---|
16 |
|
---|
17 | /** The root surface corresponds to drawing directly into the window. */
|
---|
18 | private T _rootSurface;
|
---|
19 | /** The surface that drawing commands should draw into. */
|
---|
20 | private T _currentSurface;
|
---|
21 | /** The stack of drawing surfaces. */
|
---|
22 | private Stack<T> _surfaceStack;
|
---|
23 | /** The image that produced the current drawing surface. */
|
---|
24 | private Image _currentImage;
|
---|
25 | /** The stack of images that produced the surfaces in the surface stack. */
|
---|
26 | private Stack<Image> _imageStack;
|
---|
27 | /** The clip-stack for the root surface. */
|
---|
28 | private EnforcedClipStack _rootClipStack;
|
---|
29 | /** The clip-stack for the current surface. */
|
---|
30 | private EnforcedClipStack _currentClipStack;
|
---|
31 | /** The clip-stack for each drawing surface. */
|
---|
32 | private Stack<EnforcedClipStack> _clipStackStack;
|
---|
33 |
|
---|
34 | /** Constructor specifying no root surface. */
|
---|
35 | public GraphicsSurfaceStack()
|
---|
36 | {
|
---|
37 | this(null);
|
---|
38 | }
|
---|
39 |
|
---|
40 | /** Constructor specifying the root surface. */
|
---|
41 | public GraphicsSurfaceStack(T rootSurface)
|
---|
42 | {
|
---|
43 | setRootSurface(rootSurface);
|
---|
44 | _currentImage = null;
|
---|
45 | _surfaceStack = new Stack<T>();
|
---|
46 | _imageStack = new Stack<Image>();
|
---|
47 | _rootClipStack = _currentClipStack = new EnforcedClipStack();
|
---|
48 | _clipStackStack = new Stack<EnforcedClipStack>();
|
---|
49 | }
|
---|
50 |
|
---|
51 | /** Should be overridden by sub-types to allow a drawing surface to be extracted from an image. */
|
---|
52 | public abstract T getSurfaceFromImage(Image image);
|
---|
53 |
|
---|
54 | /** Should be overridden by sub-types to set the actual clip on a given surface. */
|
---|
55 | public abstract void setSurfaceClip(T surface, Clip clip);
|
---|
56 |
|
---|
57 | /** Pushes a new image onto the stack, and sets it as the current drawing surface. */
|
---|
58 | public void push(Image image)
|
---|
59 | {
|
---|
60 | if (image == null) return;
|
---|
61 |
|
---|
62 | _currentSurface = getSurfaceFromImage(image);
|
---|
63 | _currentImage = image;
|
---|
64 | _currentClipStack = new EnforcedClipStack();
|
---|
65 | _surfaceStack.push(_currentSurface);
|
---|
66 | _imageStack.push(image);
|
---|
67 | _clipStackStack.push(_currentClipStack);
|
---|
68 | }
|
---|
69 |
|
---|
70 | /** Removes an image from the stack. The removed image is returned, or null if the root surface was current. */
|
---|
71 | public Image pop()
|
---|
72 | {
|
---|
73 | if (_surfaceStack.isEmpty()) return null;
|
---|
74 |
|
---|
75 | Image oldTop = _imageStack.pop();
|
---|
76 | _surfaceStack.pop();
|
---|
77 | _clipStackStack.pop();
|
---|
78 |
|
---|
79 | if (!_surfaceStack.isEmpty()) {
|
---|
80 | _currentSurface = _surfaceStack.peek();
|
---|
81 | _currentImage = _imageStack.peek();
|
---|
82 | _currentClipStack = _clipStackStack.peek();
|
---|
83 | } else {
|
---|
84 | _currentSurface = _rootSurface;
|
---|
85 | _currentImage = null;
|
---|
86 | _currentClipStack = _rootClipStack;
|
---|
87 | }
|
---|
88 |
|
---|
89 | return oldTop;
|
---|
90 | }
|
---|
91 |
|
---|
92 | /** Gets a reference to the current drawing surface. */
|
---|
93 | public T getCurrentSurface()
|
---|
94 | {
|
---|
95 | return _currentSurface;
|
---|
96 | }
|
---|
97 |
|
---|
98 | /** Gets a reference to the top image on the stack. */
|
---|
99 | public Image getCurrentImage()
|
---|
100 | {
|
---|
101 | return _currentImage;
|
---|
102 | }
|
---|
103 |
|
---|
104 | /** Pushes a new clip onto the stack, ensuring that it is a sub-area of the top of the stack. */
|
---|
105 | public EnforcedClipKey pushClip(Clip clip)
|
---|
106 | {
|
---|
107 | EnforcedClipKey key = _currentClipStack.push(clip);
|
---|
108 | if (key != null) ensureClip();
|
---|
109 | return key;
|
---|
110 | }
|
---|
111 |
|
---|
112 | /** Pops the top of the current clip-stack if there given key corresponds to it. */
|
---|
113 | public Clip popClip(EnforcedClipKey key)
|
---|
114 | {
|
---|
115 | Clip clip = _currentClipStack.pop(key);
|
---|
116 | if (clip != null) ensureClip();
|
---|
117 | return clip;
|
---|
118 | }
|
---|
119 |
|
---|
120 | /** Returns a copy of the top of the current clip-stack. */
|
---|
121 | public Clip peekClip()
|
---|
122 | {
|
---|
123 | return _currentClipStack.peek();
|
---|
124 | }
|
---|
125 |
|
---|
126 | /** Ensures the current clip is applied to the underlying surface. */
|
---|
127 | public void ensureClip()
|
---|
128 | {
|
---|
129 | setSurfaceClip(_currentSurface, _currentClipStack.peek());
|
---|
130 | }
|
---|
131 |
|
---|
132 | /** Updates the root surface. Does not affect any stacked image surfaces. */
|
---|
133 | public void setRootSurface(T rootSurface)
|
---|
134 | {
|
---|
135 | if (_currentSurface == _rootSurface) _currentSurface = rootSurface;
|
---|
136 | _rootSurface = rootSurface;
|
---|
137 |
|
---|
138 | }
|
---|
139 | }
|
---|