|
mam@0
|
1 |
/* |
|
Matthias@270
|
2 |
* Copyright (c) 2008-2010, Matthias Mann |
|
mam@0
|
3 |
* |
|
mam@0
|
4 |
* All rights reserved. |
|
mam@0
|
5 |
* |
|
mam@0
|
6 |
* Redistribution and use in source and binary forms, with or without |
|
mam@0
|
7 |
* modification, are permitted provided that the following conditions are met: |
|
mam@0
|
8 |
* |
|
mam@0
|
9 |
* * Redistributions of source code must retain the above copyright notice, |
|
mam@0
|
10 |
* this list of conditions and the following disclaimer. |
|
mam@0
|
11 |
* * Redistributions in binary form must reproduce the above copyright |
|
mam@0
|
12 |
* notice, this list of conditions and the following disclaimer in the |
|
mam@0
|
13 |
* documentation and/or other materials provided with the distribution. |
|
mam@0
|
14 |
* * Neither the name of Matthias Mann nor the names of its contributors may |
|
mam@0
|
15 |
* be used to endorse or promote products derived from this software |
|
mam@0
|
16 |
* without specific prior written permission. |
|
mam@0
|
17 |
* |
|
mam@0
|
18 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
mam@0
|
19 |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
mam@0
|
20 |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
mam@0
|
21 |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
|
mam@0
|
22 |
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
mam@0
|
23 |
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|
mam@0
|
24 |
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
|
mam@0
|
25 |
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
|
mam@0
|
26 |
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
|
mam@0
|
27 |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
|
mam@0
|
28 |
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
mam@0
|
29 |
*/ |
|
mam@0
|
30 |
package de.matthiasmann.twl; |
|
mam@0
|
31 |
|
|
Matthias@59
|
32 |
import de.matthiasmann.twl.model.StringModel; |
|
mam@0
|
33 |
import de.matthiasmann.twl.utils.TextUtil; |
|
mam@0
|
34 |
import de.matthiasmann.twl.utils.CallbackSupport; |
|
mam@0
|
35 |
import de.matthiasmann.twl.renderer.Font; |
|
mam@0
|
36 |
import de.matthiasmann.twl.renderer.Image; |
|
mam@0
|
37 |
import org.lwjgl.input.Keyboard; |
|
mam@0
|
38 |
|
|
mam@0
|
39 |
/** |
|
mam@0
|
40 |
* A simple one line edit field |
|
mam@0
|
41 |
* |
|
mam@0
|
42 |
* @author Matthias Mann |
|
mam@0
|
43 |
*/ |
|
mam@0
|
44 |
public class EditField extends Widget { |
|
mam@0
|
45 |
|
|
Matthias@110
|
46 |
public static final String STATE_ERROR = "error"; |
|
Matthias@233
|
47 |
public static final String STATE_READONLY = "readonly"; |
|
Matthias@358
|
48 |
public static final String STATE_HOVER = "hover"; |
|
Matthias@110
|
49 |
|
|
mam@0
|
50 |
public interface Callback { |
|
Matthias@270
|
51 |
/** |
|
Matthias@270
|
52 |
* Gets called for any change in the edit field, or when ESCAPE or RETURN was pressed |
|
Matthias@270
|
53 |
* |
|
Matthias@270
|
54 |
* @param key One of KEY_NONE, KEY_ESCAPE, KEY_RETURN |
|
Matthias@270
|
55 |
* @see Keyboard#KEY_NONE |
|
Matthias@270
|
56 |
* @see Keyboard#KEY_ESCAPE |
|
Matthias@270
|
57 |
* @see Keyboard#KEY_RETURN |
|
Matthias@270
|
58 |
*/ |
|
mam@0
|
59 |
public void callback(int key); |
|
mam@0
|
60 |
} |
|
mam@0
|
61 |
|
|
mam@0
|
62 |
private final StringBuilder editBuffer; |
|
Matthias@313
|
63 |
private final TextRenderer textRenderer; |
|
mam@0
|
64 |
private PasswordMasker passwordMasking; |
|
Matthias@59
|
65 |
private Runnable modelChangeListener; |
|
Matthias@59
|
66 |
private StringModel model; |
|
Matthias@233
|
67 |
private boolean readOnly; |
|
mam@0
|
68 |
|
|
mam@0
|
69 |
private int cursorPos; |
|
mam@0
|
70 |
private int scrollPos; |
|
mam@0
|
71 |
private int selectionStart; |
|
mam@0
|
72 |
private int selectionEnd; |
|
mam@0
|
73 |
private int maxTextLength = Short.MAX_VALUE; |
|
mam@0
|
74 |
|
|
Matthias@313
|
75 |
private int columns = 5; |
|
mam@0
|
76 |
private Image cursorImage; |
|
mam@0
|
77 |
private Image selectionImage; |
|
mam@0
|
78 |
private char passwordChar; |
|
mam@0
|
79 |
private Object errorMsg; |
|
mam@0
|
80 |
private Callback[] callbacks; |
|
mam@0
|
81 |
private PopupMenu popupMenu; |
|
Matthias@237
|
82 |
private boolean textLongerThenWidget; |
|
Matthias@270
|
83 |
|
|
Matthias@270
|
84 |
private InfoWindow autoCompletionWindow; |
|
Matthias@270
|
85 |
private boolean autoCompletionWantKeys; |
|
Matthias@270
|
86 |
private int autoCompletionHeight = 100; |
|
Matthias@352
|
87 |
|
|
Matthias@352
|
88 |
private InfoWindow errorInfoWindow; |
|
Matthias@352
|
89 |
private Label errorInfoLabel; |
|
Matthias@363
|
90 |
|
|
Matthias@363
|
91 |
/** |
|
Matthias@363
|
92 |
* Creates a new EditField with an optional parent animation state. |
|
Matthias@363
|
93 |
* |
|
Matthias@363
|
94 |
* Unlike other widgets which use the passed animation state directly, |
|
Matthias@363
|
95 |
* the EditField always creates it's animation state with the passed |
|
Matthias@363
|
96 |
* one as parent. |
|
Matthias@363
|
97 |
* |
|
Matthias@363
|
98 |
* @param parentAnimationState |
|
Matthias@363
|
99 |
* @see AnimationState#AnimationState(de.matthiasmann.twl.AnimationState) |
|
Matthias@363
|
100 |
*/ |
|
Matthias@363
|
101 |
public EditField(AnimationState parentAnimationState) { |
|
Matthias@364
|
102 |
super(parentAnimationState, true); |
|
Matthias@363
|
103 |
|
|
mam@0
|
104 |
this.editBuffer = new StringBuilder(); |
|
mam@0
|
105 |
this.textRenderer = new TextRenderer(getAnimationState()); |
|
mam@0
|
106 |
this.passwordChar = '*'; |
|
mam@0
|
107 |
|
|
mam@0
|
108 |
textRenderer.setTheme("renderer"); |
|
mam@0
|
109 |
textRenderer.setClip(true); |
|
mam@0
|
110 |
|
|
mam@0
|
111 |
add(textRenderer); |
|
mam@0
|
112 |
setCanAcceptKeyboardFocus(true); |
|
Matthias@136
|
113 |
setDepthFocusTraversal(false); |
|
Matthias@135
|
114 |
|
|
Matthias@135
|
115 |
addActionMapping("cut", "cutToClipboard"); |
|
Matthias@135
|
116 |
addActionMapping("copy", "copyToClipboard"); |
|
Matthias@135
|
117 |
addActionMapping("paste", "pasteFromClipboard"); |
|
Matthias@135
|
118 |
addActionMapping("selectAll", "selectAll"); |
|
mam@0
|
119 |
} |
|
mam@0
|
120 |
|
|
Matthias@363
|
121 |
public EditField() { |
|
Matthias@363
|
122 |
this(null); |
|
Matthias@363
|
123 |
} |
|
Matthias@363
|
124 |
|
|
mam@0
|
125 |
public void addCallback(Callback cb) { |
|
mam@0
|
126 |
callbacks = CallbackSupport.addCallbackToList(callbacks, cb, Callback.class); |
|
mam@0
|
127 |
} |
|
mam@0
|
128 |
|
|
mam@0
|
129 |
public void removeCallback(Callback cb) { |
|
Matthias@182
|
130 |
callbacks = CallbackSupport.removeCallbackFromList(callbacks, cb); |
|
mam@0
|
131 |
} |
|
mam@0
|
132 |
|
|
mam@0
|
133 |
protected void doCallback(int key) { |
|
mam@0
|
134 |
if(callbacks != null) { |
|
mam@0
|
135 |
for(Callback cb : callbacks) { |
|
mam@0
|
136 |
cb.callback(key); |
|
mam@0
|
137 |
} |
|
mam@0
|
138 |
} |
|
mam@0
|
139 |
} |
|
mam@0
|
140 |
|
|
mam@0
|
141 |
public boolean isPasswordMasking() { |
|
mam@0
|
142 |
return passwordMasking != null; |
|
mam@0
|
143 |
} |
|
mam@0
|
144 |
|
|
mam@0
|
145 |
public void setPasswordMasking(boolean passwordMasking) { |
|
mam@0
|
146 |
if(passwordMasking != isPasswordMasking()) { |
|
mam@0
|
147 |
if(passwordMasking) { |
|
mam@0
|
148 |
this.passwordMasking = new PasswordMasker(editBuffer, passwordChar); |
|
mam@0
|
149 |
} else { |
|
mam@0
|
150 |
this.passwordMasking = null; |
|
mam@0
|
151 |
} |
|
mam@0
|
152 |
updateText(); |
|
mam@0
|
153 |
} |
|
mam@0
|
154 |
} |
|
mam@0
|
155 |
|
|
mam@0
|
156 |
public char getPasswordChar() { |
|
mam@0
|
157 |
return passwordChar; |
|
mam@0
|
158 |
} |
|
mam@0
|
159 |
|
|
mam@0
|
160 |
public void setPasswordChar(char passwordChar) { |
|
mam@0
|
161 |
this.passwordChar = passwordChar; |
|
mam@0
|
162 |
if(passwordMasking != null) { |
|
mam@0
|
163 |
passwordMasking = new PasswordMasker(editBuffer, passwordChar); |
|
mam@0
|
164 |
updateText(); |
|
mam@0
|
165 |
} |
|
mam@0
|
166 |
} |
|
mam@0
|
167 |
|
|
Matthias@313
|
168 |
public int getColumns() { |
|
Matthias@313
|
169 |
return columns; |
|
Matthias@313
|
170 |
} |
|
Matthias@313
|
171 |
|
|
Matthias@313
|
172 |
/** |
|
Matthias@313
|
173 |
* This is used to determine the desired width of the EditField based on |
|
Matthias@313
|
174 |
* it's font and the character 'X' |
|
Matthias@313
|
175 |
* |
|
Matthias@313
|
176 |
* @param columns number of characters |
|
Matthias@313
|
177 |
* @throws IllegalArgumentException if columns < 0 |
|
Matthias@313
|
178 |
*/ |
|
Matthias@313
|
179 |
public void setColumns(int columns) { |
|
Matthias@313
|
180 |
if(columns < 0) { |
|
Matthias@313
|
181 |
throw new IllegalArgumentException("columns"); |
|
Matthias@313
|
182 |
} |
|
Matthias@313
|
183 |
this.columns = columns; |
|
Matthias@313
|
184 |
} |
|
Matthias@313
|
185 |
|
|
Matthias@59
|
186 |
public StringModel getModel() { |
|
Matthias@59
|
187 |
return model; |
|
Matthias@59
|
188 |
} |
|
Matthias@59
|
189 |
|
|
Matthias@59
|
190 |
public void setModel(StringModel model) { |
|
Matthias@59
|
191 |
if(this.model != null) { |
|
Matthias@59
|
192 |
this.model.removeCallback(modelChangeListener); |
|
Matthias@59
|
193 |
} |
|
Matthias@59
|
194 |
this.model = model; |
|
Matthias@59
|
195 |
if(this.model != null) { |
|
Matthias@59
|
196 |
if(modelChangeListener == null) { |
|
Matthias@59
|
197 |
modelChangeListener = new ModelChangeListener(); |
|
Matthias@59
|
198 |
} |
|
Matthias@59
|
199 |
this.model.addCallback(modelChangeListener); |
|
Matthias@59
|
200 |
modelChanged(); |
|
Matthias@59
|
201 |
} |
|
Matthias@59
|
202 |
} |
|
Matthias@59
|
203 |
|
|
mam@0
|
204 |
public void setText(String text) { |
|
mam@0
|
205 |
text = TextUtil.limitStringLength(text, maxTextLength); |
|
mam@0
|
206 |
editBuffer.replace(0, editBuffer.length(), text); |
|
mam@0
|
207 |
cursorPos = editBuffer.length(); |
|
Matthias@75
|
208 |
selectionStart = 0; |
|
Matthias@75
|
209 |
selectionEnd = 0; |
|
mam@0
|
210 |
updateText(); |
|
mam@0
|
211 |
scrollToCursor(true); |
|
mam@0
|
212 |
} |
|
mam@0
|
213 |
|
|
mam@0
|
214 |
public String getText() { |
|
mam@0
|
215 |
return editBuffer.toString(); |
|
mam@0
|
216 |
} |
|
mam@0
|
217 |
|
|
mam@0
|
218 |
public String getSelectedText() { |
|
mam@0
|
219 |
return editBuffer.substring(selectionStart, selectionEnd); |
|
mam@0
|
220 |
} |
|
mam@0
|
221 |
|
|
mam@0
|
222 |
public boolean hasSelection() { |
|
mam@0
|
223 |
return selectionStart != selectionEnd; |
|
mam@0
|
224 |
} |
|
mam@0
|
225 |
|
|
Matthias@270
|
226 |
public int getCursorPos() { |
|
Matthias@270
|
227 |
return cursorPos; |
|
Matthias@270
|
228 |
} |
|
Matthias@270
|
229 |
|
|
Matthias@270
|
230 |
public int getTextLength() { |
|
Matthias@270
|
231 |
return editBuffer.length(); |
|
Matthias@270
|
232 |
} |
|
Matthias@270
|
233 |
|
|
Matthias@233
|
234 |
public boolean isReadOnly() { |
|
Matthias@233
|
235 |
return readOnly; |
|
Matthias@233
|
236 |
} |
|
Matthias@233
|
237 |
|
|
Matthias@233
|
238 |
public void setReadOnly(boolean readOnly) { |
|
Matthias@233
|
239 |
this.readOnly = readOnly; |
|
Matthias@233
|
240 |
getAnimationState().setAnimationState(STATE_READONLY, readOnly); |
|
Matthias@233
|
241 |
} |
|
Matthias@233
|
242 |
|
|
mam@0
|
243 |
public void insertText(String str) { |
|
Matthias@233
|
244 |
if(!readOnly) { |
|
Matthias@233
|
245 |
boolean update = false; |
|
Matthias@233
|
246 |
if(hasSelection()) { |
|
Matthias@233
|
247 |
deleteSelection(); |
|
Matthias@233
|
248 |
update = true; |
|
Matthias@233
|
249 |
} |
|
Matthias@233
|
250 |
int insertLength = Math.min(str.length(), maxTextLength - editBuffer.length()); |
|
Matthias@233
|
251 |
if(insertLength > 0) { |
|
Matthias@233
|
252 |
editBuffer.insert(cursorPos, str, 0, insertLength); |
|
Matthias@233
|
253 |
cursorPos += insertLength; |
|
Matthias@233
|
254 |
update = true; |
|
Matthias@233
|
255 |
} |
|
Matthias@233
|
256 |
if(update) { |
|
Matthias@233
|
257 |
updateText(); |
|
Matthias@233
|
258 |
} |
|
mam@0
|
259 |
} |
|
mam@0
|
260 |
} |
|
mam@0
|
261 |
|
|
mam@0
|
262 |
public void pasteFromClipboard() { |
|
mam@0
|
263 |
String cbText = Clipboard.getClipboard(); |
|
mam@0
|
264 |
if(cbText != null) { |
|
mam@0
|
265 |
cbText = TextUtil.stripNewLines(cbText); |
|
mam@0
|
266 |
insertText(cbText); |
|
mam@0
|
267 |
} |
|
mam@0
|
268 |
} |
|
mam@0
|
269 |
|
|
mam@0
|
270 |
public void copyToClipboard() { |
|
mam@0
|
271 |
String text; |
|
mam@0
|
272 |
if(hasSelection()) { |
|
mam@0
|
273 |
text = getSelectedText(); |
|
mam@0
|
274 |
} else { |
|
mam@0
|
275 |
text = getText(); |
|
mam@0
|
276 |
} |
|
Matthias@71
|
277 |
if(isPasswordMasking()) { |
|
Matthias@71
|
278 |
text = TextUtil.createString(passwordChar, text.length()); |
|
Matthias@71
|
279 |
} |
|
Matthias@71
|
280 |
Clipboard.setClipboard(text); |
|
Matthias@71
|
281 |
} |
|
Matthias@71
|
282 |
|
|
Matthias@71
|
283 |
public void cutToClipboard() { |
|
Matthias@71
|
284 |
String text; |
|
Matthias@71
|
285 |
if(hasSelection()) { |
|
Matthias@71
|
286 |
text = getSelectedText(); |
|
Matthias@233
|
287 |
if(!readOnly) { |
|
Matthias@233
|
288 |
deleteSelection(); |
|
Matthias@233
|
289 |
updateText(); |
|
Matthias@233
|
290 |
} |
|
Matthias@71
|
291 |
} else { |
|
Matthias@71
|
292 |
text = getText(); |
|
Matthias@233
|
293 |
if(!readOnly) { |
|
Matthias@233
|
294 |
setText(""); |
|
Matthias@233
|
295 |
} |
|
Matthias@71
|
296 |
} |
|
Matthias@71
|
297 |
if(isPasswordMasking()) { |
|
Matthias@71
|
298 |
text = TextUtil.createString(passwordChar, text.length()); |
|
Matthias@71
|
299 |
} |
|
mam@0
|
300 |
Clipboard.setClipboard(text); |
|
mam@0
|
301 |
} |
|
mam@0
|
302 |
|
|
mam@0
|
303 |
public int getMaxTextLength() { |
|
mam@0
|
304 |
return maxTextLength; |
|
mam@0
|
305 |
} |
|
mam@0
|
306 |
|
|
mam@0
|
307 |
public void setMaxTextLength(int maxTextLength) { |
|
mam@0
|
308 |
this.maxTextLength = maxTextLength; |
|
mam@0
|
309 |
} |
|
mam@0
|
310 |
|
|
mam@0
|
311 |
@Override |
|
mam@0
|
312 |
protected void applyTheme(ThemeInfo themeInfo) { |
|
mam@0
|
313 |
super.applyTheme(themeInfo); |
|
Matthias@313
|
314 |
applayThemeEditField(themeInfo); |
|
Matthias@313
|
315 |
} |
|
Matthias@313
|
316 |
|
|
Matthias@313
|
317 |
protected void applayThemeEditField(ThemeInfo themeInfo) { |
|
mam@0
|
318 |
cursorImage = themeInfo.getImage("cursor"); |
|
mam@0
|
319 |
selectionImage = themeInfo.getImage("selection"); |
|
Matthias@270
|
320 |
autoCompletionHeight = themeInfo.getParameter("autocompletion-height", 100); |
|
Matthias@313
|
321 |
columns = themeInfo.getParameter("columns", 5); |
|
mam@0
|
322 |
setPasswordChar((char)themeInfo.getParameter("passwordChar", '*')); |
|
mam@0
|
323 |
setErrorMessage(errorMsg); // update color |
|
mam@0
|
324 |
} |
|
mam@0
|
325 |
|
|
mam@0
|
326 |
@Override |
|
mam@0
|
327 |
protected void layout() { |
|
Matthias@270
|
328 |
layoutChildFullInnerArea(textRenderer); |
|
Matthias@237
|
329 |
checkTextWidth(); |
|
Matthias@270
|
330 |
if(autoCompletionWindow != null) { |
|
Matthias@270
|
331 |
layoutAutocompletionWindow(); |
|
Matthias@270
|
332 |
} |
|
Matthias@352
|
333 |
if(errorInfoWindow != null) { |
|
Matthias@352
|
334 |
layoutErrorInfoWindow(); |
|
Matthias@352
|
335 |
} |
|
mam@0
|
336 |
} |
|
Matthias@270
|
337 |
|
|
Matthias@270
|
338 |
private void layoutAutocompletionWindow() { |
|
Matthias@270
|
339 |
autoCompletionWindow.setPosition(getX(), getBottom()); |
|
Matthias@270
|
340 |
autoCompletionWindow.setSize(getWidth(), autoCompletionHeight); |
|
Matthias@270
|
341 |
} |
|
Matthias@270
|
342 |
|
|
Matthias@8
|
343 |
private int computeInnerWidth() { |
|
Matthias@313
|
344 |
if(columns > 0) { |
|
Matthias@313
|
345 |
Font font = textRenderer.getFont(); |
|
Matthias@313
|
346 |
if(font != null) { |
|
Matthias@313
|
347 |
return font.computeTextWidth("X")*columns; |
|
Matthias@313
|
348 |
} |
|
Matthias@8
|
349 |
} |
|
Matthias@8
|
350 |
return 0; |
|
Matthias@8
|
351 |
} |
|
Matthias@8
|
352 |
|
|
Matthias@8
|
353 |
private int computeInnerHeight() { |
|
Matthias@8
|
354 |
Font font = textRenderer.getFont(); |
|
Matthias@8
|
355 |
if(font != null) { |
|
Matthias@8
|
356 |
return font.getLineHeight(); |
|
Matthias@8
|
357 |
} |
|
Matthias@8
|
358 |
return 0; |
|
Matthias@8
|
359 |
} |
|
Matthias@8
|
360 |
|
|
Matthias@8
|
361 |
@Override |
|
Matthias@8
|
362 |
public int getMinWidth() { |
|
Matthias@8
|
363 |
int minWidth = super.getMinWidth(); |
|
Matthias@8
|
364 |
minWidth = Math.max(minWidth, computeInnerWidth() + getBorderHorizontal()); |
|
Matthias@8
|
365 |
return minWidth; |
|
Matthias@8
|
366 |
} |
|
Matthias@8
|
367 |
|
|
Matthias@8
|
368 |
@Override |
|
Matthias@8
|
369 |
public int getMinHeight() { |
|
Matthias@8
|
370 |
int minHeight = super.getMinHeight(); |
|
Matthias@8
|
371 |
minHeight = Math.max(minHeight, computeInnerHeight() + getBorderVertical()); |
|
Matthias@8
|
372 |
return minHeight; |
|
Matthias@8
|
373 |
} |
|
mam@0
|
374 |
|
|
mam@0
|
375 |
@Override |
|
Matthias@42
|
376 |
public int getPreferredInnerWidth() { |
|
Matthias@8
|
377 |
return computeInnerWidth(); |
|
mam@0
|
378 |
} |
|
mam@0
|
379 |
|
|
mam@0
|
380 |
@Override |
|
Matthias@42
|
381 |
public int getPreferredInnerHeight() { |
|
Matthias@8
|
382 |
return computeInnerHeight(); |
|
mam@0
|
383 |
} |
|
mam@0
|
384 |
|
|
mam@0
|
385 |
public void setErrorMessage(Object errorMsg) { |
|
Matthias@110
|
386 |
getAnimationState().setAnimationState(STATE_ERROR, errorMsg != null); |
|
mam@0
|
387 |
if(this.errorMsg != errorMsg) { |
|
mam@0
|
388 |
this.errorMsg = errorMsg; |
|
mam@0
|
389 |
GUI gui = getGUI(); |
|
mam@0
|
390 |
if(gui != null) { |
|
mam@0
|
391 |
gui.requestToolTipUpdate(this); |
|
mam@0
|
392 |
} |
|
mam@0
|
393 |
} |
|
Matthias@352
|
394 |
if(errorMsg != null) { |
|
Matthias@352
|
395 |
if(hasKeyboardFocus()) { |
|
Matthias@352
|
396 |
openErrorInfoWindow(); |
|
Matthias@352
|
397 |
} |
|
Matthias@352
|
398 |
} else if(errorInfoWindow != null) { |
|
Matthias@352
|
399 |
errorInfoWindow.closeInfo(); |
|
Matthias@352
|
400 |
} |
|
mam@0
|
401 |
} |
|
mam@0
|
402 |
|
|
mam@0
|
403 |
@Override |
|
mam@0
|
404 |
public Object getTooltipContent() { |
|
mam@0
|
405 |
if(errorMsg != null) { |
|
mam@0
|
406 |
return errorMsg; |
|
mam@0
|
407 |
} |
|
Matthias@237
|
408 |
Object tooltip = super.getTooltipContent(); |
|
Matthias@238
|
409 |
if(tooltip == null && !isPasswordMasking() && textLongerThenWidget) { |
|
Matthias@237
|
410 |
tooltip = getText(); |
|
Matthias@237
|
411 |
} |
|
Matthias@237
|
412 |
return tooltip; |
|
mam@0
|
413 |
} |
|
mam@0
|
414 |
|
|
Matthias@270
|
415 |
public void setAutoCompletionWindow(InfoWindow window, boolean wantKeys) { |
|
Matthias@270
|
416 |
if(window == null) { |
|
Matthias@270
|
417 |
if(autoCompletionWindow != null) { |
|
Matthias@270
|
418 |
autoCompletionWindow.closeInfo(); |
|
Matthias@270
|
419 |
autoCompletionWindow = null; |
|
Matthias@270
|
420 |
} |
|
Matthias@270
|
421 |
autoCompletionWantKeys = false; |
|
Matthias@270
|
422 |
} else { |
|
Matthias@270
|
423 |
autoCompletionWindow = window; |
|
Matthias@270
|
424 |
autoCompletionWantKeys = wantKeys; |
|
Matthias@270
|
425 |
if(autoCompletionWindow.openInfo()) { |
|
Matthias@270
|
426 |
layoutAutocompletionWindow(); |
|
Matthias@270
|
427 |
} |
|
Matthias@270
|
428 |
} |
|
Matthias@270
|
429 |
} |
|
Matthias@270
|
430 |
|
|
mam@0
|
431 |
@Override |
|
mam@0
|
432 |
public boolean handleEvent(Event evt) { |
|
mam@0
|
433 |
boolean selectPressed = (evt.getModifiers() & Event.MODIFIER_SHIFT) != 0; |
|
mam@0
|
434 |
|
|
Matthias@358
|
435 |
if(evt.isMouseEvent()) { |
|
Matthias@358
|
436 |
boolean hover = (evt.getType() != Event.Type.MOUSE_EXITED) && isMouseInside(evt); |
|
Matthias@358
|
437 |
getAnimationState().setAnimationState(STATE_HOVER, hover); |
|
Matthias@358
|
438 |
} |
|
Matthias@358
|
439 |
|
|
mam@0
|
440 |
if(evt.isMouseDragEvent()) { |
|
mam@0
|
441 |
if(evt.getType() == Event.Type.MOUSE_DRAGED && |
|
mam@0
|
442 |
(evt.getModifiers() & Event.MODIFIER_LBUTTON) != 0) { |
|
mam@0
|
443 |
int newPos = textRenderer.getCursorPosFromMouse(evt.getMouseX()); |
|
mam@0
|
444 |
setCursorPos(newPos, true); |
|
mam@0
|
445 |
} |
|
mam@0
|
446 |
return true; |
|
mam@0
|
447 |
} |
|
mam@0
|
448 |
|
|
Matthias@135
|
449 |
if(super.handleEvent(evt)) { |
|
Matthias@135
|
450 |
return true; |
|
Matthias@135
|
451 |
} |
|
Matthias@135
|
452 |
|
|
Matthias@270
|
453 |
if(evt.isKeyEvent() && autoCompletionWantKeys) { |
|
Matthias@270
|
454 |
if(autoCompletionWindow.handleEvent(evt)) { |
|
Matthias@270
|
455 |
return true; |
|
Matthias@270
|
456 |
} |
|
Matthias@270
|
457 |
} |
|
Matthias@270
|
458 |
|
|
mam@0
|
459 |
switch (evt.getType()) { |
|
mam@0
|
460 |
case KEY_PRESSED: |
|
mam@0
|
461 |
switch (evt.getKeyCode()) { |
|
mam@0
|
462 |
case Keyboard.KEY_BACK: |
|
mam@0
|
463 |
deletePrev(); |
|
mam@0
|
464 |
return true; |
|
mam@0
|
465 |
case Keyboard.KEY_DELETE: |
|
mam@0
|
466 |
deleteNext(); |
|
mam@0
|
467 |
return true; |
|
mam@0
|
468 |
case Keyboard.KEY_RETURN: |
|
mam@0
|
469 |
case Keyboard.KEY_ESCAPE: |
|
mam@0
|
470 |
doCallback(evt.getKeyCode()); |
|
mam@0
|
471 |
return true; |
|
mam@0
|
472 |
case Keyboard.KEY_HOME: |
|
mam@0
|
473 |
setCursorPos(0, selectPressed); |
|
mam@0
|
474 |
return true; |
|
mam@0
|
475 |
case Keyboard.KEY_END: |
|
mam@0
|
476 |
setCursorPos(editBuffer.length(), selectPressed); |
|
mam@0
|
477 |
return true; |
|
mam@0
|
478 |
case Keyboard.KEY_LEFT: |
|
mam@0
|
479 |
moveCursor(-1, selectPressed); |
|
mam@0
|
480 |
return true; |
|
mam@0
|
481 |
case Keyboard.KEY_RIGHT: |
|
mam@0
|
482 |
moveCursor(+1, selectPressed); |
|
mam@0
|
483 |
return true; |
|
Matthias@270
|
484 |
case Keyboard.KEY_UP: |
|
Matthias@270
|
485 |
case Keyboard.KEY_DOWN: |
|
Matthias@270
|
486 |
if(!autoCompletionWantKeys && autoCompletionWindow != null) { |
|
Matthias@270
|
487 |
return autoCompletionWindow.handleEvent(evt); |
|
Matthias@270
|
488 |
} |
|
Matthias@270
|
489 |
return false; |
|
Matthias@124
|
490 |
default: |
|
Matthias@124
|
491 |
if(evt.hasKeyChar()) { |
|
Matthias@124
|
492 |
insertChar(evt.getKeyChar()); |
|
Matthias@124
|
493 |
return true; |
|
Matthias@124
|
494 |
} |
|
Matthias@234
|
495 |
return false; |
|
mam@0
|
496 |
} |
|
Matthias@234
|
497 |
|
|
Matthias@234
|
498 |
case KEY_RELEASED: |
|
Matthias@234
|
499 |
switch (evt.getKeyCode()) { |
|
Matthias@234
|
500 |
case Keyboard.KEY_BACK: |
|
Matthias@234
|
501 |
case Keyboard.KEY_DELETE: |
|
Matthias@234
|
502 |
case Keyboard.KEY_RETURN: |
|
Matthias@234
|
503 |
case Keyboard.KEY_ESCAPE: |
|
Matthias@234
|
504 |
case Keyboard.KEY_HOME: |
|
Matthias@234
|
505 |
case Keyboard.KEY_END: |
|
Matthias@234
|
506 |
case Keyboard.KEY_LEFT: |
|
Matthias@234
|
507 |
case Keyboard.KEY_RIGHT: |
|
Matthias@234
|
508 |
return true; |
|
Matthias@270
|
509 |
case Keyboard.KEY_UP: |
|
Matthias@270
|
510 |
case Keyboard.KEY_DOWN: |
|
Matthias@270
|
511 |
if(!autoCompletionWantKeys && autoCompletionWindow != null) { |
|
Matthias@270
|
512 |
return autoCompletionWindow.handleEvent(evt); |
|
Matthias@270
|
513 |
} |
|
Matthias@270
|
514 |
return false; |
|
Matthias@234
|
515 |
default: |
|
Matthias@234
|
516 |
return evt.hasKeyChar(); |
|
Matthias@234
|
517 |
} |
|
mam@0
|
518 |
|
|
mam@0
|
519 |
case MOUSE_BTNUP: |
|
mam@0
|
520 |
if(evt.getMouseButton() == Event.MOUSE_RBUTTON && isMouseInside(evt)) { |
|
mam@0
|
521 |
showPopupMenu(evt); |
|
mam@0
|
522 |
return true; |
|
mam@0
|
523 |
} |
|
mam@0
|
524 |
break; |
|
mam@0
|
525 |
|
|
mam@0
|
526 |
case MOUSE_BTNDOWN: |
|
mam@0
|
527 |
if(evt.getMouseButton() == Event.MOUSE_LBUTTON && isMouseInside(evt)) { |
|
mam@0
|
528 |
int newPos = textRenderer.getCursorPosFromMouse(evt.getMouseX()); |
|
mam@0
|
529 |
setCursorPos(newPos, selectPressed); |
|
mam@0
|
530 |
return true; |
|
mam@0
|
531 |
} |
|
mam@0
|
532 |
break; |
|
Matthias@50
|
533 |
|
|
Matthias@50
|
534 |
case MOUSE_CLICKED: |
|
Matthias@50
|
535 |
if(evt.getMouseClickCount() == 2) { |
|
Matthias@50
|
536 |
int newPos = textRenderer.getCursorPosFromMouse(evt.getMouseX()); |
|
Matthias@50
|
537 |
selectWordFromMouse(newPos); |
|
Matthias@50
|
538 |
return true; |
|
Matthias@50
|
539 |
} |
|
Matthias@50
|
540 |
if(evt.getMouseClickCount() == 3) { |
|
Matthias@50
|
541 |
selectAll(); |
|
Matthias@50
|
542 |
return true; |
|
Matthias@50
|
543 |
} |
|
Matthias@50
|
544 |
break; |
|
Matthias@387
|
545 |
|
|
Matthias@387
|
546 |
case MOUSE_WHEEL: |
|
Matthias@387
|
547 |
return false; |
|
mam@0
|
548 |
} |
|
mam@0
|
549 |
|
|
mam@0
|
550 |
return evt.isMouseEvent(); |
|
mam@0
|
551 |
} |
|
mam@0
|
552 |
|
|
mam@0
|
553 |
protected void showPopupMenu(Event evt) { |
|
mam@0
|
554 |
if(popupMenu == null) { |
|
mam@0
|
555 |
popupMenu = createPopupMenu(); |
|
mam@0
|
556 |
} |
|
mam@0
|
557 |
if(popupMenu != null) { |
|
mam@0
|
558 |
popupMenu.showPopup(evt.getMouseX(), evt.getMouseY()); |
|
mam@0
|
559 |
} |
|
mam@0
|
560 |
} |
|
mam@0
|
561 |
|
|
mam@0
|
562 |
protected PopupMenu createPopupMenu() { |
|
Matthias@71
|
563 |
Button btnCut = new Button("cut"); |
|
Matthias@71
|
564 |
btnCut.addCallback(new Runnable() { |
|
Matthias@71
|
565 |
public void run() { |
|
Matthias@71
|
566 |
cutToClipboard(); |
|
Matthias@71
|
567 |
} |
|
Matthias@71
|
568 |
}); |
|
Matthias@71
|
569 |
|
|
mam@0
|
570 |
Button btnCopy = new Button("copy"); |
|
mam@0
|
571 |
btnCopy.addCallback(new Runnable() { |
|
mam@0
|
572 |
public void run() { |
|
mam@0
|
573 |
copyToClipboard(); |
|
mam@0
|
574 |
} |
|
mam@0
|
575 |
}); |
|
mam@0
|
576 |
|
|
Matthias@71
|
577 |
Button btnPaste = new Button("paste"); |
|
Matthias@71
|
578 |
btnPaste.addCallback(new Runnable() { |
|
Matthias@71
|
579 |
public void run() { |
|
Matthias@71
|
580 |
pasteFromClipboard(); |
|
Matthias@71
|
581 |
} |
|
Matthias@71
|
582 |
}); |
|
Matthias@71
|
583 |
|
|
mam@0
|
584 |
Button btnClear = new Button("clear"); |
|
mam@0
|
585 |
btnClear.addCallback(new Runnable() { |
|
mam@0
|
586 |
public void run() { |
|
Matthias@233
|
587 |
if(!isReadOnly()) { |
|
Matthias@233
|
588 |
setText(""); |
|
Matthias@233
|
589 |
} |
|
mam@0
|
590 |
} |
|
mam@0
|
591 |
}); |
|
mam@0
|
592 |
|
|
mam@0
|
593 |
PopupMenu menu = new PopupMenu(this); |
|
Matthias@71
|
594 |
menu.add(btnCut); |
|
mam@0
|
595 |
menu.add(btnCopy); |
|
Matthias@71
|
596 |
menu.add(btnPaste); |
|
Matthias@71
|
597 |
menu.addSpacer(); |
|
mam@0
|
598 |
menu.add(btnClear); |
|
mam@0
|
599 |
return menu; |
|
mam@0
|
600 |
} |
|
mam@0
|
601 |
|
|
mam@0
|
602 |
private void updateText() { |
|
Matthias@59
|
603 |
if(model != null) { |
|
Matthias@59
|
604 |
model.setValue(getText()); |
|
Matthias@59
|
605 |
} |
|
Matthias@415
|
606 |
textRenderer.setCharSequence(passwordMasking != null ? passwordMasking : editBuffer); |
|
Matthias@237
|
607 |
checkTextWidth(); |
|
mam@0
|
608 |
scrollToCursor(false); |
|
mam@0
|
609 |
doCallback(Keyboard.KEY_NONE); |
|
mam@0
|
610 |
} |
|
mam@0
|
611 |
|
|
Matthias@237
|
612 |
private void checkTextWidth() { |
|
Matthias@237
|
613 |
textLongerThenWidget = textRenderer.getPreferredWidth() > textRenderer.getWidth(); |
|
Matthias@237
|
614 |
} |
|
Matthias@237
|
615 |
|
|
mam@0
|
616 |
protected void moveCursor(int dir, boolean select) { |
|
mam@0
|
617 |
setCursorPos(cursorPos + dir, select); |
|
mam@0
|
618 |
} |
|
mam@0
|
619 |
|
|
mam@0
|
620 |
protected void setCursorPos(int pos, boolean select) { |
|
mam@0
|
621 |
pos = Math.max(0, Math.min(editBuffer.length(), pos)); |
|
mam@0
|
622 |
if(!select) { |
|
mam@0
|
623 |
selectionStart = pos; |
|
mam@0
|
624 |
selectionEnd = pos; |
|
mam@0
|
625 |
} |
|
mam@0
|
626 |
if(this.cursorPos != pos) { |
|
mam@0
|
627 |
if(select) { |
|
mam@0
|
628 |
if(hasSelection()) { |
|
mam@0
|
629 |
if(cursorPos == selectionStart) { |
|
mam@0
|
630 |
selectionStart = pos; |
|
mam@0
|
631 |
} else { |
|
mam@0
|
632 |
selectionEnd = pos; |
|
mam@0
|
633 |
} |
|
mam@0
|
634 |
} else { |
|
mam@0
|
635 |
selectionStart = cursorPos; |
|
mam@0
|
636 |
selectionEnd = pos; |
|
mam@0
|
637 |
} |
|
mam@0
|
638 |
if(selectionStart > selectionEnd) { |
|
mam@0
|
639 |
int t = selectionStart; |
|
mam@0
|
640 |
selectionStart = selectionEnd; |
|
mam@0
|
641 |
selectionEnd = t; |
|
mam@0
|
642 |
} |
|
mam@0
|
643 |
} |
|
mam@0
|
644 |
|
|
mam@0
|
645 |
this.cursorPos = pos; |
|
mam@0
|
646 |
scrollToCursor(false); |
|
mam@0
|
647 |
} |
|
mam@0
|
648 |
} |
|
mam@0
|
649 |
|
|
Matthias@135
|
650 |
public void selectAll() { |
|
Matthias@50
|
651 |
selectionStart = 0; |
|
Matthias@50
|
652 |
selectionEnd = editBuffer.length(); |
|
Matthias@50
|
653 |
} |
|
Matthias@50
|
654 |
|
|
Matthias@50
|
655 |
protected void selectWordFromMouse(int index) { |
|
Matthias@50
|
656 |
selectionStart = index; |
|
Matthias@50
|
657 |
selectionEnd = index; |
|
Matthias@50
|
658 |
while(selectionStart > 0 && !Character.isWhitespace(editBuffer.charAt(selectionStart-1))) { |
|
Matthias@50
|
659 |
selectionStart--; |
|
Matthias@50
|
660 |
} |
|
Matthias@50
|
661 |
while(selectionEnd < editBuffer.length() && !Character.isWhitespace(editBuffer.charAt(selectionEnd))) { |
|
Matthias@50
|
662 |
selectionEnd++; |
|
Matthias@50
|
663 |
} |
|
Matthias@50
|
664 |
} |
|
Matthias@50
|
665 |
|
|
mam@0
|
666 |
protected void scrollToCursor(boolean force) { |
|
mam@0
|
667 |
int xpos = textRenderer.computeRelativeCursorPositionX(cursorPos); |
|
mam@0
|
668 |
int renderWidth = textRenderer.getWidth() - 5; |
|
mam@0
|
669 |
if(xpos < scrollPos + 5) { |
|
mam@0
|
670 |
scrollPos = Math.max(0, xpos - 5); |
|
mam@0
|
671 |
} else if(force || xpos - scrollPos > renderWidth) { |
|
mam@0
|
672 |
scrollPos = Math.max(0, xpos - renderWidth); |
|
mam@0
|
673 |
} |
|
mam@0
|
674 |
} |
|
mam@0
|
675 |
|
|
mam@0
|
676 |
protected void insertChar(char ch) { |
|
mam@0
|
677 |
// don't add control characters |
|
Matthias@233
|
678 |
if(!readOnly && !Character.isISOControl(ch)) { |
|
mam@0
|
679 |
boolean update = false; |
|
mam@0
|
680 |
if(hasSelection()) { |
|
mam@0
|
681 |
deleteSelection(); |
|
mam@0
|
682 |
update = true; |
|
mam@0
|
683 |
} |
|
mam@0
|
684 |
if(editBuffer.length() < maxTextLength) { |
|
mam@0
|
685 |
editBuffer.insert(cursorPos, ch); |
|
mam@0
|
686 |
cursorPos++; |
|
mam@0
|
687 |
update = true; |
|
mam@0
|
688 |
} |
|
mam@0
|
689 |
if(update) { |
|
mam@0
|
690 |
updateText(); |
|
mam@0
|
691 |
} |
|
mam@0
|
692 |
} |
|
mam@0
|
693 |
} |
|
mam@0
|
694 |
|
|
mam@0
|
695 |
protected void deletePrev() { |
|
Matthias@233
|
696 |
if(!readOnly) { |
|
Matthias@233
|
697 |
if(hasSelection()) { |
|
Matthias@233
|
698 |
deleteSelection(); |
|
Matthias@233
|
699 |
updateText(); |
|
Matthias@233
|
700 |
} else if(cursorPos > 0) { |
|
Matthias@233
|
701 |
--cursorPos; |
|
Matthias@233
|
702 |
deleteNext(); |
|
Matthias@233
|
703 |
} |
|
mam@0
|
704 |
} |
|
mam@0
|
705 |
} |
|
mam@0
|
706 |
|
|
mam@0
|
707 |
protected void deleteNext() { |
|
Matthias@233
|
708 |
if(!readOnly) { |
|
Matthias@233
|
709 |
if(hasSelection()) { |
|
Matthias@233
|
710 |
deleteSelection(); |
|
Matthias@233
|
711 |
updateText(); |
|
Matthias@233
|
712 |
} else if(cursorPos < editBuffer.length()) { |
|
Matthias@233
|
713 |
editBuffer.deleteCharAt(cursorPos); |
|
Matthias@233
|
714 |
updateText(); |
|
Matthias@233
|
715 |
} |
|
mam@0
|
716 |
} |
|
mam@0
|
717 |
} |
|
mam@0
|
718 |
|
|
mam@0
|
719 |
protected void deleteSelection() { |
|
mam@0
|
720 |
editBuffer.delete(selectionStart, selectionEnd); |
|
mam@0
|
721 |
selectionEnd = selectionStart; |
|
mam@0
|
722 |
setCursorPos(selectionStart, false); |
|
mam@0
|
723 |
} |
|
mam@0
|
724 |
|
|
Matthias@59
|
725 |
protected void modelChanged() { |
|
Matthias@59
|
726 |
String modelText = model.getValue(); |
|
Matthias@59
|
727 |
if(editBuffer.length() != modelText.length() || !getText().equals(modelText)) { |
|
Matthias@59
|
728 |
setText(modelText); |
|
Matthias@59
|
729 |
} |
|
Matthias@59
|
730 |
} |
|
Matthias@59
|
731 |
|
|
Matthias@71
|
732 |
protected boolean hasFocusOrPopup() { |
|
Matthias@71
|
733 |
return hasKeyboardFocus() || hasOpenPopups(); |
|
Matthias@71
|
734 |
} |
|
Matthias@71
|
735 |
|
|
Matthias@67
|
736 |
@Override |
|
Matthias@67
|
737 |
protected void paintOverlay(GUI gui) { |
|
Matthias@71
|
738 |
if(cursorImage != null && hasFocusOrPopup()) { |
|
Matthias@67
|
739 |
int xpos = textRenderer.lastTextX + textRenderer.computeRelativeCursorPositionX(cursorPos); |
|
Matthias@67
|
740 |
cursorImage.draw(getAnimationState(), xpos, textRenderer.computeTextY(), |
|
Matthias@67
|
741 |
cursorImage.getWidth(), textRenderer.getFont().getLineHeight()); |
|
Matthias@67
|
742 |
} |
|
Matthias@67
|
743 |
super.paintOverlay(gui); |
|
Matthias@67
|
744 |
} |
|
Matthias@67
|
745 |
|
|
Matthias@352
|
746 |
private void openErrorInfoWindow() { |
|
Matthias@352
|
747 |
if(autoCompletionWindow == null || !autoCompletionWindow.isOpen()) { |
|
Matthias@352
|
748 |
if(errorInfoWindow == null) { |
|
Matthias@352
|
749 |
errorInfoLabel = new Label(); |
|
Matthias@352
|
750 |
errorInfoWindow = new InfoWindow(this); |
|
Matthias@352
|
751 |
errorInfoWindow.setTheme("editfield-errorinfowindow"); |
|
Matthias@352
|
752 |
errorInfoWindow.add(errorInfoLabel); |
|
Matthias@352
|
753 |
} |
|
Matthias@352
|
754 |
errorInfoLabel.setText(errorMsg.toString()); |
|
Matthias@352
|
755 |
errorInfoWindow.openInfo(); |
|
Matthias@352
|
756 |
layoutErrorInfoWindow(); |
|
Matthias@352
|
757 |
} |
|
Matthias@352
|
758 |
} |
|
Matthias@352
|
759 |
|
|
Matthias@352
|
760 |
private void layoutErrorInfoWindow() { |
|
Matthias@352
|
761 |
errorInfoWindow.setSize(getWidth(), errorInfoWindow.getPreferredHeight()); |
|
Matthias@352
|
762 |
errorInfoWindow.setPosition(getX(), getBottom()); |
|
Matthias@352
|
763 |
} |
|
Matthias@352
|
764 |
|
|
Matthias@352
|
765 |
@Override |
|
Matthias@352
|
766 |
protected void keyboardFocusGained() { |
|
Matthias@352
|
767 |
if(errorMsg != null) { |
|
Matthias@352
|
768 |
openErrorInfoWindow(); |
|
Matthias@352
|
769 |
} |
|
Matthias@352
|
770 |
} |
|
Matthias@352
|
771 |
|
|
Matthias@352
|
772 |
@Override |
|
Matthias@352
|
773 |
protected void keyboardFocusLost() { |
|
Matthias@352
|
774 |
super.keyboardFocusLost(); |
|
Matthias@352
|
775 |
if(errorInfoWindow != null) { |
|
Matthias@352
|
776 |
errorInfoWindow.closeInfo(); |
|
Matthias@352
|
777 |
} |
|
Matthias@352
|
778 |
} |
|
Matthias@352
|
779 |
|
|
Matthias@59
|
780 |
protected class ModelChangeListener implements Runnable { |
|
Matthias@59
|
781 |
public void run() { |
|
Matthias@59
|
782 |
modelChanged(); |
|
Matthias@59
|
783 |
} |
|
Matthias@59
|
784 |
} |
|
Matthias@59
|
785 |
|
|
mam@0
|
786 |
protected class TextRenderer extends TextWidget { |
|
mam@0
|
787 |
int lastTextX; |
|
mam@0
|
788 |
|
|
mam@0
|
789 |
protected TextRenderer(AnimationState animState) { |
|
mam@0
|
790 |
super(animState); |
|
mam@0
|
791 |
} |
|
mam@0
|
792 |
|
|
mam@0
|
793 |
@Override |
|
mam@0
|
794 |
protected void paintWidget(GUI gui) { |
|
mam@0
|
795 |
lastTextX = computeTextX(); |
|
Matthias@71
|
796 |
if(hasSelection() && hasFocusOrPopup()) { |
|
mam@0
|
797 |
if(selectionImage != null) { |
|
mam@0
|
798 |
int xpos0 = lastTextX + computeRelativeCursorPositionX(selectionStart); |
|
mam@0
|
799 |
int xpos1 = lastTextX + computeRelativeCursorPositionX(selectionEnd); |
|
mam@0
|
800 |
selectionImage.draw(getAnimationState(), xpos0, computeTextY(), |
|
mam@0
|
801 |
xpos1 - xpos0, getFont().getLineHeight()); |
|
mam@0
|
802 |
} |
|
Matthias@110
|
803 |
paintWithSelection(getAnimationState(), selectionStart, selectionEnd); |
|
Matthias@110
|
804 |
} else { |
|
Matthias@110
|
805 |
paintLabelText(getAnimationState()); |
|
mam@0
|
806 |
} |
|
mam@0
|
807 |
} |
|
mam@0
|
808 |
|
|
mam@0
|
809 |
@Override |
|
mam@0
|
810 |
protected void sizeChanged() { |
|
mam@0
|
811 |
scrollToCursor(true); |
|
mam@0
|
812 |
} |
|
mam@0
|
813 |
|
|
mam@0
|
814 |
@Override |
|
mam@0
|
815 |
protected int computeTextX() { |
|
Matthias@125
|
816 |
if(hasFocusOrPopup()) { |
|
mam@0
|
817 |
return getInnerX() - scrollPos; |
|
mam@0
|
818 |
} else { |
|
mam@0
|
819 |
return getInnerX(); |
|
mam@0
|
820 |
} |
|
mam@0
|
821 |
} |
|
mam@0
|
822 |
|
|
mam@0
|
823 |
protected int getCursorPosFromMouse(int x) { |
|
mam@0
|
824 |
if(getFont() != null) { |
|
mam@0
|
825 |
x += getFont().getSpaceWidth() / 2; |
|
mam@0
|
826 |
return getFont().computeVisibleGlpyhs( |
|
mam@0
|
827 |
getText(), 0, editBuffer.length(), |
|
mam@0
|
828 |
x - lastTextX); |
|
mam@0
|
829 |
} else { |
|
mam@0
|
830 |
return 0; |
|
mam@0
|
831 |
} |
|
mam@0
|
832 |
} |
|
mam@0
|
833 |
} |
|
mam@0
|
834 |
|
|
mam@0
|
835 |
static class PasswordMasker implements CharSequence { |
|
mam@0
|
836 |
private final CharSequence base; |
|
mam@0
|
837 |
private final char maskingChar; |
|
mam@0
|
838 |
|
|
mam@0
|
839 |
public PasswordMasker(CharSequence base, char maskingChar) { |
|
mam@0
|
840 |
this.base = base; |
|
mam@0
|
841 |
this.maskingChar = maskingChar; |
|
mam@0
|
842 |
} |
|
mam@0
|
843 |
|
|
mam@0
|
844 |
public int length() { |
|
mam@0
|
845 |
return base.length(); |
|
mam@0
|
846 |
} |
|
mam@0
|
847 |
|
|
mam@0
|
848 |
public char charAt(int index) { |
|
mam@0
|
849 |
return maskingChar; |
|
mam@0
|
850 |
} |
|
mam@0
|
851 |
|
|
mam@0
|
852 |
public CharSequence subSequence(int start, int end) { |
|
mam@0
|
853 |
throw new UnsupportedOperationException("Not supported."); |
|
mam@0
|
854 |
} |
|
mam@0
|
855 |
} |
|
mam@0
|
856 |
|
|
mam@0
|
857 |
} |