|
Matthias@161
|
1 |
/* |
|
Matthias@161
|
2 |
* Copyright (c) 2008-2010, Matthias Mann |
|
Matthias@161
|
3 |
* |
|
Matthias@161
|
4 |
* All rights reserved. |
|
Matthias@161
|
5 |
* |
|
Matthias@161
|
6 |
* Redistribution and use in source and binary forms, with or without |
|
Matthias@161
|
7 |
* modification, are permitted provided that the following conditions are met: |
|
Matthias@161
|
8 |
* |
|
Matthias@161
|
9 |
* * Redistributions of source code must retain the above copyright notice, |
|
Matthias@161
|
10 |
* this list of conditions and the following disclaimer. |
|
Matthias@161
|
11 |
* * Redistributions in binary form must reproduce the above copyright |
|
Matthias@161
|
12 |
* notice, this list of conditions and the following disclaimer in the |
|
Matthias@161
|
13 |
* documentation and/or other materials provided with the distribution. |
|
Matthias@161
|
14 |
* * Neither the name of Matthias Mann nor the names of its contributors may |
|
Matthias@161
|
15 |
* be used to endorse or promote products derived from this software |
|
Matthias@161
|
16 |
* without specific prior written permission. |
|
Matthias@161
|
17 |
* |
|
Matthias@161
|
18 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
Matthias@161
|
19 |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
Matthias@161
|
20 |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
Matthias@161
|
21 |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
|
Matthias@161
|
22 |
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
Matthias@161
|
23 |
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|
Matthias@161
|
24 |
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
|
Matthias@161
|
25 |
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
|
Matthias@161
|
26 |
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
|
Matthias@161
|
27 |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
|
Matthias@161
|
28 |
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
Matthias@161
|
29 |
*/ |
|
Matthias@161
|
30 |
package textarea; |
|
Matthias@161
|
31 |
|
|
Matthias@161
|
32 |
import de.matthiasmann.twl.DesktopArea; |
|
Matthias@161
|
33 |
import de.matthiasmann.twl.Event; |
|
Matthias@161
|
34 |
import de.matthiasmann.twl.FPSCounter; |
|
Matthias@161
|
35 |
import de.matthiasmann.twl.GUI; |
|
Matthias@194
|
36 |
import de.matthiasmann.twl.Rect; |
|
Matthias@161
|
37 |
import de.matthiasmann.twl.ResizableFrame; |
|
Matthias@161
|
38 |
import de.matthiasmann.twl.ScrollPane; |
|
Matthias@161
|
39 |
import de.matthiasmann.twl.TextArea; |
|
Matthias@186
|
40 |
import de.matthiasmann.twl.Timer; |
|
Matthias@163
|
41 |
import de.matthiasmann.twl.ValueAdjusterInt; |
|
Matthias@173
|
42 |
import de.matthiasmann.twl.textarea.HTMLTextAreaModel; |
|
Matthias@163
|
43 |
import de.matthiasmann.twl.model.SimpleIntegerModel; |
|
Matthias@161
|
44 |
import de.matthiasmann.twl.renderer.lwjgl.LWJGLRenderer; |
|
Matthias@186
|
45 |
import de.matthiasmann.twl.textarea.StyleAttribute; |
|
Matthias@178
|
46 |
import de.matthiasmann.twl.textarea.StyleSheet; |
|
Matthias@186
|
47 |
import de.matthiasmann.twl.textarea.TextAreaModel; |
|
Matthias@186
|
48 |
import de.matthiasmann.twl.textarea.Value; |
|
Matthias@161
|
49 |
import de.matthiasmann.twl.theme.ThemeManager; |
|
Matthias@180
|
50 |
import de.matthiasmann.twl.utils.TextUtil; |
|
Matthias@161
|
51 |
import java.io.IOException; |
|
Matthias@161
|
52 |
import java.util.logging.Level; |
|
Matthias@161
|
53 |
import java.util.logging.Logger; |
|
Matthias@161
|
54 |
import org.lwjgl.opengl.Display; |
|
Matthias@161
|
55 |
import org.lwjgl.opengl.DisplayMode; |
|
Matthias@161
|
56 |
import org.lwjgl.opengl.GL11; |
|
Matthias@253
|
57 |
import test.TestUtils; |
|
Matthias@161
|
58 |
|
|
Matthias@161
|
59 |
/** |
|
Matthias@161
|
60 |
* |
|
Matthias@161
|
61 |
* @author Matthias Mann |
|
Matthias@161
|
62 |
*/ |
|
Matthias@161
|
63 |
public class TextAreaDemo extends DesktopArea { |
|
Matthias@161
|
64 |
|
|
Matthias@161
|
65 |
public static void main(String[] args) { |
|
Matthias@161
|
66 |
try { |
|
Matthias@161
|
67 |
Display.setDisplayMode(new DisplayMode(800, 600)); |
|
Matthias@161
|
68 |
Display.create(); |
|
Matthias@161
|
69 |
Display.setTitle("TWL TextArea Demo"); |
|
Matthias@161
|
70 |
Display.setVSyncEnabled(true); |
|
Matthias@161
|
71 |
|
|
Matthias@161
|
72 |
LWJGLRenderer renderer = new LWJGLRenderer(); |
|
Matthias@161
|
73 |
TextAreaDemo demo = new TextAreaDemo(); |
|
Matthias@161
|
74 |
GUI gui = new GUI(demo, renderer); |
|
Matthias@161
|
75 |
|
|
Matthias@161
|
76 |
ThemeManager theme = ThemeManager.createThemeManager( |
|
Matthias@161
|
77 |
TextAreaDemo.class.getResource("demo.xml"), renderer); |
|
Matthias@161
|
78 |
gui.applyTheme(theme); |
|
Matthias@161
|
79 |
|
|
Matthias@161
|
80 |
while(!Display.isCloseRequested() && !demo.quit) { |
|
Matthias@161
|
81 |
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT); |
|
Matthias@161
|
82 |
|
|
Matthias@161
|
83 |
gui.update(); |
|
Matthias@165
|
84 |
|
|
Matthias@165
|
85 |
/** |
|
Matthias@165
|
86 |
* requires LWJGL 2.4 - for 2.3 just call Display.update() |
|
Matthias@165
|
87 |
*/ |
|
Matthias@165
|
88 |
Display.update(false); |
|
Matthias@165
|
89 |
GL11.glGetError(); // force sync with multi threaded GL driver |
|
Matthias@165
|
90 |
Display.sync(60); // ensure 60Hz even without vsync |
|
Matthias@165
|
91 |
Display.processMessages(); // now process inputs |
|
Matthias@161
|
92 |
} |
|
Matthias@161
|
93 |
|
|
Matthias@161
|
94 |
gui.destroy(); |
|
Matthias@161
|
95 |
theme.destroy(); |
|
Matthias@161
|
96 |
} catch (Exception ex) { |
|
Matthias@253
|
97 |
TestUtils.showErrMsg(ex); |
|
Matthias@161
|
98 |
} |
|
Matthias@161
|
99 |
Display.destroy(); |
|
Matthias@161
|
100 |
} |
|
Matthias@161
|
101 |
|
|
Matthias@161
|
102 |
private final FPSCounter fpsCounter; |
|
Matthias@161
|
103 |
private final TextFrame textFrame; |
|
Matthias@161
|
104 |
|
|
Matthias@161
|
105 |
public boolean quit; |
|
Matthias@161
|
106 |
|
|
Matthias@161
|
107 |
public TextAreaDemo() { |
|
Matthias@161
|
108 |
fpsCounter = new FPSCounter(); |
|
Matthias@161
|
109 |
add(fpsCounter); |
|
Matthias@161
|
110 |
|
|
Matthias@161
|
111 |
textFrame = new TextFrame(); |
|
Matthias@161
|
112 |
add(textFrame); |
|
Matthias@161
|
113 |
|
|
Matthias@161
|
114 |
textFrame.setSize(600, 500); |
|
Matthias@161
|
115 |
textFrame.setPosition(40, 20); |
|
Matthias@161
|
116 |
} |
|
Matthias@161
|
117 |
|
|
Matthias@161
|
118 |
@Override |
|
Matthias@161
|
119 |
protected void layout() { |
|
Matthias@161
|
120 |
super.layout(); |
|
Matthias@161
|
121 |
|
|
Matthias@161
|
122 |
// fpsCounter is bottom right |
|
Matthias@161
|
123 |
fpsCounter.adjustSize(); |
|
Matthias@161
|
124 |
fpsCounter.setPosition( |
|
Matthias@161
|
125 |
getInnerWidth() - fpsCounter.getWidth(), |
|
Matthias@161
|
126 |
getInnerHeight() - fpsCounter.getHeight()); |
|
Matthias@161
|
127 |
} |
|
Matthias@161
|
128 |
|
|
Matthias@161
|
129 |
@Override |
|
Matthias@161
|
130 |
protected boolean handleEvent(Event evt) { |
|
Matthias@161
|
131 |
if(super.handleEvent(evt)) { |
|
Matthias@161
|
132 |
return true; |
|
Matthias@161
|
133 |
} |
|
Matthias@161
|
134 |
switch (evt.getType()) { |
|
Matthias@161
|
135 |
case KEY_PRESSED: |
|
Matthias@161
|
136 |
switch (evt.getKeyCode()) { |
|
Matthias@197
|
137 |
case Event.KEY_ESCAPE: |
|
Matthias@161
|
138 |
quit = true; |
|
Matthias@161
|
139 |
return true; |
|
Matthias@161
|
140 |
} |
|
Matthias@161
|
141 |
} |
|
Matthias@161
|
142 |
return false; |
|
Matthias@161
|
143 |
} |
|
Matthias@161
|
144 |
|
|
Matthias@161
|
145 |
static class TextFrame extends ResizableFrame { |
|
Matthias@161
|
146 |
private final HTMLTextAreaModel textAreaModel; |
|
Matthias@161
|
147 |
private final TextArea textArea; |
|
Matthias@161
|
148 |
private final ScrollPane scrollPane; |
|
Matthias@186
|
149 |
private Timer timer; |
|
Matthias@186
|
150 |
private int size; |
|
Matthias@186
|
151 |
private int dir; |
|
Matthias@186
|
152 |
|
|
Matthias@186
|
153 |
private static final int MIN_SIZE = 128; |
|
Matthias@186
|
154 |
private static final int MAX_SIZE = 256; |
|
Matthias@161
|
155 |
|
|
Matthias@161
|
156 |
public TextFrame() { |
|
Matthias@161
|
157 |
setTitle("Text"); |
|
Matthias@161
|
158 |
|
|
Matthias@161
|
159 |
this.textAreaModel = new HTMLTextAreaModel(); |
|
Matthias@161
|
160 |
this.textArea = new TextArea(textAreaModel); |
|
Matthias@161
|
161 |
|
|
Matthias@177
|
162 |
readFile("demo.html"); |
|
Matthias@161
|
163 |
|
|
Matthias@161
|
164 |
textArea.addCallback(new TextArea.Callback() { |
|
Matthias@161
|
165 |
public void handleLinkClicked(String href) { |
|
Matthias@186
|
166 |
if(href.startsWith("javascript:")) { |
|
Matthias@186
|
167 |
handleAction(href.substring(11)); |
|
Matthias@194
|
168 |
} else if(href.startsWith("#")) { |
|
Matthias@195
|
169 |
TextAreaModel.Element ankor = textAreaModel.getElementById(href.substring(1)); |
|
Matthias@194
|
170 |
if(ankor != null) { |
|
Matthias@194
|
171 |
Rect rect = textArea.getElementRect(ankor); |
|
Matthias@194
|
172 |
if(rect != null) { |
|
Matthias@194
|
173 |
scrollPane.setScrollPositionY(rect.getY()); |
|
Matthias@194
|
174 |
} |
|
Matthias@194
|
175 |
} |
|
Matthias@186
|
176 |
} else { |
|
Matthias@186
|
177 |
readFile(href); |
|
Matthias@186
|
178 |
} |
|
Matthias@161
|
179 |
} |
|
Matthias@161
|
180 |
}); |
|
Matthias@161
|
181 |
|
|
Matthias@163
|
182 |
ValueAdjusterInt vai = new ValueAdjusterInt(new SimpleIntegerModel(0, 100, 50)); |
|
Matthias@163
|
183 |
vai.setTooltipContent("Select a nice value"); |
|
Matthias@163
|
184 |
textArea.registerWidget("niceValueSlider", vai); |
|
Matthias@163
|
185 |
|
|
Matthias@161
|
186 |
scrollPane = new ScrollPane(textArea); |
|
Matthias@161
|
187 |
scrollPane.setFixed(ScrollPane.Fixed.HORIZONTAL); |
|
Matthias@161
|
188 |
|
|
Matthias@161
|
189 |
add(scrollPane); |
|
Matthias@161
|
190 |
} |
|
Matthias@177
|
191 |
|
|
Matthias@186
|
192 |
@Override |
|
Matthias@186
|
193 |
protected void afterAddToGUI(GUI gui) { |
|
Matthias@186
|
194 |
super.afterAddToGUI(gui); |
|
Matthias@186
|
195 |
timer = gui.createTimer(); |
|
Matthias@186
|
196 |
timer.setDelay(16); |
|
Matthias@186
|
197 |
timer.setContinuous(true); |
|
Matthias@186
|
198 |
timer.setCallback(new Runnable() { |
|
Matthias@186
|
199 |
public void run() { |
|
Matthias@186
|
200 |
animate(); |
|
Matthias@186
|
201 |
} |
|
Matthias@186
|
202 |
}); |
|
Matthias@186
|
203 |
} |
|
Matthias@186
|
204 |
|
|
Matthias@186
|
205 |
@Override |
|
Matthias@186
|
206 |
protected void beforeRemoveFromGUI(GUI gui) { |
|
Matthias@186
|
207 |
super.beforeRemoveFromGUI(gui); |
|
Matthias@186
|
208 |
timer.stop(); |
|
Matthias@186
|
209 |
timer = null; |
|
Matthias@186
|
210 |
} |
|
Matthias@186
|
211 |
|
|
Matthias@177
|
212 |
void readFile(String name) { |
|
Matthias@177
|
213 |
try { |
|
Matthias@177
|
214 |
textAreaModel.readHTMLFromURL(TextAreaDemo.class.getResource(name)); |
|
Matthias@180
|
215 |
|
|
Matthias@180
|
216 |
StyleSheet styleSheet = new StyleSheet(); |
|
Matthias@180
|
217 |
for(String styleSheetLink : textAreaModel.getStyleSheetLinks()) { |
|
Matthias@180
|
218 |
try { |
|
Matthias@180
|
219 |
styleSheet.parse(TextAreaDemo.class.getResource(styleSheetLink)); |
|
Matthias@180
|
220 |
} catch(IOException ex) { |
|
Matthias@180
|
221 |
Logger.getLogger(TextAreaDemo.class.getName()).log(Level.SEVERE, |
|
Matthias@180
|
222 |
"Can't parse style sheet: " + styleSheetLink, ex); |
|
Matthias@180
|
223 |
} |
|
Matthias@180
|
224 |
} |
|
Matthias@180
|
225 |
textArea.setStyleClassResolver(styleSheet); |
|
Matthias@180
|
226 |
|
|
Matthias@180
|
227 |
setTitle(TextUtil.notNull(textAreaModel.getTitle())); |
|
Matthias@186
|
228 |
|
|
Matthias@186
|
229 |
size = MIN_SIZE; |
|
Matthias@186
|
230 |
dir = -4; |
|
Matthias@177
|
231 |
} catch(IOException ex) { |
|
Matthias@177
|
232 |
Logger.getLogger(TextAreaDemo.class.getName()).log(Level.SEVERE, "Can't read HTML: " + name, ex); |
|
Matthias@177
|
233 |
} |
|
Matthias@177
|
234 |
} |
|
Matthias@186
|
235 |
|
|
Matthias@186
|
236 |
void handleAction(String what) { |
|
Matthias@186
|
237 |
if("zoomImage()".equals(what)) { |
|
Matthias@186
|
238 |
if(timer != null && !timer.isRunning()) { |
|
Matthias@186
|
239 |
dir = -dir; |
|
Matthias@186
|
240 |
timer.start(); |
|
Matthias@186
|
241 |
} |
|
Matthias@186
|
242 |
} |
|
Matthias@186
|
243 |
} |
|
Matthias@186
|
244 |
|
|
Matthias@186
|
245 |
void animate() { |
|
Matthias@186
|
246 |
size = Math.max(MIN_SIZE, Math.min(MAX_SIZE, size + dir)); |
|
Matthias@186
|
247 |
if(size == MIN_SIZE || size == MAX_SIZE) { |
|
Matthias@186
|
248 |
timer.stop(); |
|
Matthias@186
|
249 |
} |
|
Matthias@186
|
250 |
|
|
Matthias@251
|
251 |
TextAreaModel.Element e = textAreaModel.getElementById("portrait"); |
|
Matthias@186
|
252 |
if(e != null) { |
|
Matthias@186
|
253 |
e.setStyle(e.getStyle().with(StyleAttribute.WIDTH, new Value(size, Value.Unit.PX))); |
|
Matthias@186
|
254 |
textAreaModel.domModified(); |
|
Matthias@186
|
255 |
} |
|
Matthias@186
|
256 |
} |
|
Matthias@161
|
257 |
} |
|
Matthias@161
|
258 |
} |