📄 thinlet.java
字号:
/* Thinlet GUI toolkit - www.thinlet.com
* Copyright (C) 2002-2003 Robert Bajzat (robert.bajzat@thinlet.com)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
package thinlet;
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.image.*;
import java.awt.event.*;
import java.lang.reflect.*;
import java.io.*;
import java.net.*;
import java.util.*;
/**
*
*/
public class Thinlet extends Container
implements Runnable, Serializable {
private transient Font font;
private transient Color c_bg;
private transient Color c_text;
private transient Color c_textbg;
private transient Color c_border;
private transient Color c_disable;
private transient Color c_hover;
private transient Color c_press;
private transient Color c_focus;
private transient Color c_select;
private transient Color c_ctrl = null;
private transient int block;
private transient Image hgradient, vgradient;
private transient Thread timer;
private transient long watchdelay;
private transient long watch;
private transient String clipboard;
private transient ResourceBundle resourcebundle; // for internationalization
private static ResourceBundle langResource = null; // for I18N
private static ResourceBundle langResourceDefault = null; // for I18N
private transient boolean allI18n = false; // for I18N
// enter the starting characters of a list item text within a short time to select
private transient String findprefix = "";
private transient long findtime;
private Object content = createImpl("desktop");
private transient Object mouseinside;
private transient Object insidepart;
private transient Object mousepressed;
private transient Object pressedpart;
private transient int referencex, referencey;
private transient int mousex, mousey;
private transient Object focusowner;
private transient boolean focusinside;
private transient Object popupowner;
private transient Object tooltipowner;
//private transient int pressedkey;
private static final int DRAG_ENTERED = AWTEvent.RESERVED_ID_MAX + 1;
private static final int DRAG_EXITED = AWTEvent.RESERVED_ID_MAX + 2;
private static long WHEEL_MASK = 0;
private static int MOUSE_WHEEL = 0;
private static Method wheelrotation = null;
private static int evm = 0;
static {
try {
WHEEL_MASK = AWTEvent.class.getField("MOUSE_WHEEL_EVENT_MASK").getLong(null);
MOUSE_WHEEL = MouseEvent.class.getField("MOUSE_WHEEL").getInt(null);
} catch (Exception exc) { /* not 1.4 */ }
}
{
setFont(new Font("SansSerif", Font.PLAIN, 12));
//setFont((Font) getToolkit().getDesktopProperty("win.messagebox.font"));
setColors(0xe6e6e6, 0x000000, 0xffffff,
0x909090, 0xb0b0b0, 0xededed, 0xb9b9b9, 0x89899a, 0xc5c5dd);
// disable global focus-manager for this component in 1.4
if (MOUSE_WHEEL != 0) {
try {
getClass().getMethod("setFocusTraversalKeysEnabled", new Class[] { Boolean.TYPE }).
invoke(this, new Object[] { Boolean.FALSE });
} catch (Exception exc) { /* never */ }
}
// set listeners flags
enableEvents(AWTEvent.COMPONENT_EVENT_MASK |
AWTEvent.FOCUS_EVENT_MASK | AWTEvent.KEY_EVENT_MASK |
AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK | WHEEL_MASK);
// EVM has larger fillRect, fillOval, and drawImage(part), others are correct
// contributed by Ibsen Ramos-Bonilla
try {
if (System.getProperty("java.vendor").indexOf("Insignia") != -1) { evm = -1; }
} catch (Exception exc) { /* never */ }
}
/**
* Sets the 9 colors used for components, and repaints the whole UI
*
* @param background the backround of panels (dialogs, desktops),
* and disabled controls, not editable texts, lines between list items
* (the default value if <i>#e6e6e6</i>)
* @param text for text, arrow foreground (<i>black</i> by default)
* @param textbackground the background of text components, and lists
* (<i>white</i> by default)
* @param border for outer in inner borders of enabled components
* (<i>#909090</i> by default)
* @param disable for text, border, arrow color in disabled components
* (<i>#b0b0b0</i> by default)
* @param hover indicates that the mouse is inside a button area
* (<i>#ededed</i> by default)
* @param press for pressed buttons,
* gradient image is calculated using the background and this press color
* (<i>#b9b9b9</i> by default)
* @param focus for text caret and rectagle color marking the focus owner
* (<i>#89899a</i> by default)
* @param select used as the background of selected text, and list items,
* and in slider (<i>#c5c5dd</i> by default)
*/
public void setColors(int background, int text, int textbackground,
int border, int disable, int hover, int press,
int focus, int select) {
c_bg = new Color(background); c_text = new Color(text);
c_textbg = new Color(textbackground); c_border = new Color(border);
c_disable = new Color(disable); c_hover = new Color(hover);
c_press = new Color(press); c_focus = new Color(focus);
c_select = new Color(select);
hgradient = vgradient = null;
repaint();
}
//setDesktopProperty+
/**
* Sets the only one font used everywhere, and revalidates the whole UI.
* Scrollbar width/height, spinbox, and combobox button width,
* and slider size is the same as the font height
*
* @param font the default font is <i>SansSerif</i>, <i>plain</i>, and <i>12pt</i>
*/
public void setFont(Font font) {
block = getFontMetrics(font).getHeight();
super.setFont(font);
this.font = font;
hgradient = vgradient = null;
if (content != null) validate(content);
}
/**
*
*/
private void doLayout(Object component) {
String classname = getClass(component);
if ("combobox" == classname) {
if (getBoolean(component, "editable", true)) {
Image icon = getIcon(component, "icon", null);
layoutField(component, block, false,
(icon != null) ? icon.getWidth(this) : 0);
} // set editable -> validate (overwrite textfield repaint)
else {
int selected = getInteger(component, "selected", -1);
if (selected != -1) { //...
Object choice = getItem(component, selected);
set(component, "text", get(choice, "text"));
set(component, "icon", get(choice, "icon"));
}
}
}
else if (("textfield" == classname) || ("passwordfield" == classname)) {
layoutField(component, 0, ("passwordfield" == classname), 0);
}
else if ("textarea" == classname) {
String text = getString(component, "text", "");
int start = getInteger(component, "start", 0);
if (start > text.length()) { setInteger(component, "start", start = text.length(), 0); }
int end = getInteger(component, "end", 0);
if (end > text.length()) { setInteger(component, "end", end = text.length(), 0); }
boolean wrap = getBoolean(component, "wrap", false);
char[] chars = null;
if (wrap) {
Rectangle bounds = getRectangle(component, "bounds");
chars = getChars(component, text, true, bounds.width - 4, bounds.height);
if (chars == null) { // need scrollbars
chars = getChars(component, text, true, bounds.width - block - 4, 0);
}
}
else {
chars = getChars(component, text, false, 0, 0);
}
Font currentfont = (Font) get(component, "font");
FontMetrics fm = getFontMetrics((currentfont != null) ? currentfont : font);
int width = 0, height = 0;
int caretx = 0; int carety = 0;
for (int i = 0, j = 0; j <= chars.length; j++) {
if ((j == chars.length) || (chars[j] == '\n')) {
width = Math.max(width, fm.charsWidth(chars, i, j - i));
if ((end >= i) && (end <= j)) {
caretx = fm.charsWidth(chars, i, end - i);
carety = height;
}
height += fm.getHeight();
i = j + 1;
}
}
layoutScroll(component, width + 2, height - fm.getLeading() + 2, 0, 0, 0, 0,
getBoolean(component, "border", true), 0);
scrollToVisible(component, caretx, carety, 2, fm.getAscent() + fm.getDescent() + 2); //?
}
else if ("tabbedpane" == classname) {
// tabbedpane (not selected) tab padding are 1, 3, 1, and 3 pt
Rectangle bounds = getRectangle(component, "bounds");
String placement = getString(component, "placement", "top");
boolean horizontal = ((placement == "top") || (placement == "bottom"));
boolean stacked = (placement == "stacked");
// draw up tabs in row/column
int tabd = 0; Rectangle first = null; // x/y location of tab left/top
int tabsize = 0; // max height/width of tabs
for (Object tab = get(component, ":comp"); tab != null; tab = get(tab, ":next")) {
if ((tabd == 0) && ((first = getRectangle(tab, "bounds")) != null)) {
tabd = horizontal ? first.x : first.y; // restore previous offset
}
Dimension d = getSize(tab, stacked ? 8 : horizontal ? 12 : 9,
stacked ? 3 : horizontal ? 5 : 8);
setRectangle(tab, "bounds", horizontal ? tabd : 0, horizontal ? 0 : tabd,
stacked ? bounds.width : d.width, d.height);
if (stacked) {
tabd += d.height;
} else {
tabd += (horizontal ? d.width : d.height) - 3;
tabsize = Math.max(tabsize, horizontal ? d.height : d.width);
}
}
// match tab height/width, set tab content size
int cx = (placement == "left") ? (tabsize + 1) : 2;
int cy = (placement == "top") ? (tabsize + 1) : 2;
int cwidth = bounds.width - ((horizontal || stacked) ? 4 : (tabsize + 3));
int cheight = bounds.height - (stacked ? (tabd + 3) :
(horizontal ? (tabsize + 3) : 4));
for (Object tab = get(component, ":comp"); tab != null; tab = get(tab, ":next")) {
Rectangle r = getRectangle(tab, "bounds");
if (!stacked) {
if (horizontal) {
if (placement == "bottom") { r.y = bounds.height - tabsize; }
r.height = tabsize;
}
else {
if (placement == "right") { r.x = bounds.width - tabsize; }
r.width = tabsize;
}
}
Object comp = get(tab, ":comp"); // relative to the tab location
if ((comp != null) && getBoolean(comp, "visible", true)) {
setRectangle(comp, "bounds",
cx - r.x, stacked ? (r.height + 1) : (cy - r.y), cwidth, cheight);
doLayout(comp);
}
}
checkOffset(component);
}
else if (("panel" == classname) || (classname == "dialog")) {
int gap = getInteger(component, "gap", 0);
int[][] grid = getGrid(component, gap);
int top = 0; int left = 0;
int contentwidth = 0; int contentheight = 0;
if (grid != null) { // has subcomponents
top = getInteger(component, "top", 0);
left = getInteger(component, "left", 0);
int bottom = getInteger(component, "bottom", 0);
int right = getInteger(component, "right", 0);
// sums the preferred size of cell widths and heights, gaps
contentwidth = left + getSum(grid[0], 0, grid[0].length, gap, false) + right;
contentheight = top + getSum(grid[1], 0, grid[1].length, gap, false) + bottom;
}
Dimension title = getSize(component, 0, 0); // title text and icon
setInteger(component, ":titleheight", title.height, 0);
boolean scrollable = getBoolean(component, "scrollable", false);
boolean border = ("panel" == classname) && getBoolean(component, "border", false);
int iborder = (border ? 1 : 0);
if (scrollable) { // set scrollpane areas
if ("panel" == classname) {
int head = title.height / 2;
int headgap = (title.height > 0) ? (title.height - head - iborder) : 0;
scrollable = layoutScroll(component, contentwidth, contentheight,
head, 0, 0, 0, border, headgap);
}
else { // dialog
scrollable = layoutScroll(component, contentwidth, contentheight,
3 + title.height, 3, 3, 3, true, 0);
}
}
if (!scrollable) { // clear scrollpane bounds //+
set(component, ":view", null); set(component, ":port", null);
}
if (grid != null) {
int areax = 0; int areay = 0; int areawidth = 0; int areaheight = 0;
if (scrollable) {
// components are relative to the viewport
Rectangle view = getRectangle(component, ":view");
areawidth = view.width; areaheight = view.height;
}
else { // scrollpane isn't required
// components are relative to top/left corner
Rectangle bounds = getRectangle(component, "bounds");
areawidth = bounds.width; areaheight = bounds.height;
if ("panel" == classname) {
areax = iborder; areay = Math.max(iborder, title.height);
areawidth -= 2 * iborder; areaheight -= areay + iborder;
}
else { // dialog
areax = 4; areay = 4 + title.height;
areawidth -= 8; areaheight -= areay + 4;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -