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.EnforcedClipStack.EnforcedClipKey;
|
---|
8 | import org.expeditee.core.Image;
|
---|
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 to
|
---|
13 | * 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 | this(null);
|
---|
37 | }
|
---|
38 |
|
---|
39 | /** Constructor specifying the root surface. */
|
---|
40 | public GraphicsSurfaceStack(T rootSurface) {
|
---|
41 | setRootSurface(rootSurface);
|
---|
42 | _currentImage = null;
|
---|
43 | _surfaceStack = new Stack<T>();
|
---|
44 | _imageStack = new Stack<Image>();
|
---|
45 | _rootClipStack = _currentClipStack = new EnforcedClipStack();
|
---|
46 | _clipStackStack = new Stack<EnforcedClipStack>();
|
---|
47 | }
|
---|
48 |
|
---|
49 | /**
|
---|
50 | * Should be overridden by sub-types to allow a drawing surface to be extracted
|
---|
51 | * from an image.
|
---|
52 | */
|
---|
53 | public abstract T getSurfaceFromImage(Image image);
|
---|
54 |
|
---|
55 | /**
|
---|
56 | * Should be overridden by sub-types to set the actual clip on a given surface.
|
---|
57 | */
|
---|
58 | public abstract void setSurfaceClip(T surface, Clip clip);
|
---|
59 |
|
---|
60 | /**
|
---|
61 | * Pushes a new image onto the stack, and sets it as the current drawing
|
---|
62 | * surface.
|
---|
63 | */
|
---|
64 | public void push(Image image) {
|
---|
65 | if (image == null) {
|
---|
66 | return;
|
---|
67 | }
|
---|
68 |
|
---|
69 | _currentSurface = getSurfaceFromImage(image);
|
---|
70 | _currentImage = image;
|
---|
71 | _currentClipStack = new EnforcedClipStack();
|
---|
72 | _surfaceStack.push(_currentSurface);
|
---|
73 | _imageStack.push(image);
|
---|
74 | _clipStackStack.push(_currentClipStack);
|
---|
75 |
|
---|
76 | }
|
---|
77 |
|
---|
78 | /**
|
---|
79 | * Removes an image from the stack. The removed image is returned, or null if
|
---|
80 | * the root surface was current.
|
---|
81 | */
|
---|
82 | public Image pop() {
|
---|
83 | if (_surfaceStack.isEmpty()) {
|
---|
84 | return null;
|
---|
85 | }
|
---|
86 |
|
---|
87 | Image oldTop = _imageStack.pop();
|
---|
88 | _surfaceStack.pop();
|
---|
89 | _clipStackStack.pop();
|
---|
90 |
|
---|
91 | if (!_surfaceStack.isEmpty()) {
|
---|
92 | _currentSurface = _surfaceStack.peek();
|
---|
93 | _currentImage = _imageStack.peek();
|
---|
94 | _currentClipStack = _clipStackStack.peek();
|
---|
95 | } else {
|
---|
96 | _currentSurface = _rootSurface;
|
---|
97 | _currentImage = null;
|
---|
98 | _currentClipStack = _rootClipStack;
|
---|
99 | }
|
---|
100 |
|
---|
101 | return oldTop;
|
---|
102 | }
|
---|
103 |
|
---|
104 | /** Gets a reference to the current drawing surface. */
|
---|
105 | public T getCurrentSurface() {
|
---|
106 | return _currentSurface;
|
---|
107 | }
|
---|
108 |
|
---|
109 | /** Gets a reference to the top image on the stack. */
|
---|
110 | public Image getCurrentImage() {
|
---|
111 | return _currentImage;
|
---|
112 | }
|
---|
113 |
|
---|
114 | /**
|
---|
115 | * Pushes a new clip onto the stack, ensuring that it is a sub-area of the top
|
---|
116 | * of the stack.
|
---|
117 | */
|
---|
118 | public EnforcedClipKey pushClip(Clip clip) {
|
---|
119 | EnforcedClipKey key = _currentClipStack.push(clip);
|
---|
120 | if (key != null) {
|
---|
121 | ensureClip();
|
---|
122 | }
|
---|
123 | return key;
|
---|
124 | }
|
---|
125 |
|
---|
126 | /**
|
---|
127 | * Pops the top of the current clip-stack if there given key corresponds to it.
|
---|
128 | */
|
---|
129 | public Clip popClip(EnforcedClipKey key) {
|
---|
130 | Clip clip = _currentClipStack.pop(key);
|
---|
131 | if (clip != null) {
|
---|
132 | ensureClip();
|
---|
133 | }
|
---|
134 | return clip;
|
---|
135 | }
|
---|
136 |
|
---|
137 | /** Returns a copy of the top of the current clip-stack. */
|
---|
138 | public Clip peekClip() {
|
---|
139 | return _currentClipStack.peek();
|
---|
140 | }
|
---|
141 |
|
---|
142 | /** Ensures the current clip is applied to the underlying surface. */
|
---|
143 | public void ensureClip() {
|
---|
144 | setSurfaceClip(_currentSurface, _currentClipStack.peek());
|
---|
145 | }
|
---|
146 |
|
---|
147 | /** Updates the root surface. Does not affect any stacked image surfaces. */
|
---|
148 | public void setRootSurface(T rootSurface) {
|
---|
149 | if (_currentSurface == _rootSurface) {
|
---|
150 | _currentSurface = rootSurface;
|
---|
151 | }
|
---|
152 | _rootSurface = rootSurface;
|
---|
153 |
|
---|
154 | }
|
---|
155 | }
|
---|