/********************************************************************************* * TotalCross Software Development Kit * * Copyright (C) 1998, 1999 Wabasoft <www.wabasoft.com> * * Copyright (C) 2000-2012 SuperWaba Ltda. * * All Rights Reserved * * * * This library and virtual machine 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. * * * * This file is covered by the GNU LESSER GENERAL PUBLIC LICENSE VERSION 3.0 * * A copy of this license is located in file license.txt at the root of this * * SDK or can be downloaded here: * * http://www.gnu.org/licenses/lgpl-3.0.txt * * * *********************************************************************************/ package totalcross.ui; import totalcross.res.*; import totalcross.sys.*; import totalcross.ui.event.*; import totalcross.ui.gfx.*; import totalcross.ui.image.*; /** * Check is a control with a box and a check inside of it when the state is checked. * <p> * Here is an example showing a check being used: * * <pre> * public class MyProgram extends MainWindow * { * Check check; * * public void initUI() * { * add(check = new Check("Check me"), LEFT, AFTER); * } * * public void onEvent(Event event) * { * if (event.type == ControlEvent.PRESSED && event.target == check) * { * bool checked = check.isChecked(); * ... handle check being pressed * </pre> */ public class Check extends Control { private String text; private boolean checked; private int cbColor, cfColor; private int fourColors[] = new int[4]; private String []lines = Label.emptyStringArray; private int []linesW; private int lastASW; private String originalText; /** Set to true to left-justify the text in the control. The default is right-justified, * if the control's width is greater than the preferred one. * @since TotalCross 1.0 * @deprecated Now the align is always at left */ public boolean leftJustify; /** Sets the text color of the check. Defaults to the foreground color. * @since TotalCross 2.0. */ public int textColor = -1; /** Set to the color of the check, if you want to make it different of the foreground color. * @since TotalCross 1.3 */ public int checkColor = -1; /** Set to true to let the Check split its text based on the width every time its width * changes. If the height is PREFERRED, the Label will change its size accordingly. * You may change the height again calling setRect. * @since TotalCross 1.14 */ public boolean autoSplit; // guich@tc114_74 /** Creates a check control displaying the given text. */ public Check(String text) { setText(text); } /** Called by the system to pass events to the check control. */ public void onEvent(Event event) { if (event.target != this || !isEnabled()) return; switch (event.type) { case KeyEvent.ACTION_KEY_PRESS: checked = !checked; repaintNow(); postPressedEvent(); break; default: if (!isActionEvent(event)) break; PenEvent pe = (PenEvent)event; if (isInsideOrNear(pe.x,pe.y)) { Window.needsPaint = true; checked = !checked; postPressedEvent(); } break; } } /** Sets the text that is displayed in the check. */ public void setText(String text) { originalText = text; this.text = text; lines = text.equals("") ? new String[]{""} : Convert.tokenizeString(text,'\n'); // guich@tc100: now we use \n onFontChanged(); Window.needsPaint = true; } /** Gets the text displayed in the check. */ public String getText() { return text; } /** Returns the checked state of the control. */ public boolean isChecked() { return checked; } /** Sets the checked state of the control. */ public void setChecked(boolean checked) { setChecked(checked,Settings.sendPressEventOnChange); } /** Sets the checked state of the control, and send the press event if desired. */ public void setChecked(boolean checked, boolean sendPress) { if (this.checked != checked) { this.checked = checked; Window.needsPaint = true; if (sendPress) postPressedEvent(); } } /** Returns the maximum text width for the lines of this Label. */ public int getMaxTextWidth() { int w = 0; for (int i =lines.length-1; i >= 0; i--) if (linesW[i] > w) // guich@450_36: why call stringWidth if linesW has everything? w = linesW[i]; return w; } /** returns the preffered width of this control. */ public int getPreferredWidth() { return getMaxTextWidth() + fmH+Edit.prefH+2; } /** returns the preffered height of this control. */ public int getPreferredHeight() { return fmH*lines.length+Edit.prefH; } protected void onColorsChanged(boolean colorsChanged) { cbColor = UIColors.sameColors ? backColor : Color.brighter(getBackColor()); // guich@572_15 cfColor = getForeColor(); if (!uiAndroid) Graphics.compute3dColors(isEnabled(),backColor,foreColor,fourColors); } /** Called by the system to draw the check control. */ public void onPaint(Graphics g) { boolean enabled = isEnabled(); int wh = lines.length == 1 ? height : fmH+Edit.prefH; int xx,yy; // guich@200b4_126: repaint the background of the whole control g.backColor = backColor; if (!transparentBackground) g.fillRect(0,0,width,height); // square paint if (!uiAndroid && uiVista && enabled) // guich@573_6 g.fillVistaRect(0,0,wh,wh,cbColor,true,false); else if (!uiAndroid || !transparentBackground) { g.backColor = uiAndroid ? backColor : cbColor; g.fillRect(0,0,wh,wh); // guich@220_28 } if (uiAndroid) try { NinePatch.tryDrawImage(g, enabled ? Resources.checkBkg.getNormalInstance(wh,wh,foreColor) : Resources.checkBkg.getDisabledInstance(wh,wh,foreColor),0,0); if (checked) NinePatch.tryDrawImage(g,Resources.checkSel.getPressedInstance(wh,wh,backColor,checkColor != -1 ? checkColor : foreColor,enabled),0,0); } catch (ImageException ie) {} else g.draw3dRect(0,0,wh,wh,Graphics.R3D_CHECK,false,false,fourColors); // guich@220_28 g.foreColor = checkColor != -1 ? checkColor : uiAndroid ? foreColor : cfColor; if (!uiAndroid && checked) paintCheck(g, fmH, wh); // draw label yy = (this.height - fmH*lines.length) >> 1; xx = wh+2; // guich@300_69 g.foreColor = textColor != -1 ? (enabled ? textColor : Color.interpolate(textColor,backColor)) : cfColor; for (int i =0; i < lines.length; i++,yy+=fmH) g.drawText(lines[i], xx, yy, textShadowColor != -1, textShadowColor); } /** Paints a check in the given coordinates. The g must have been translated to destination x,y coordinates. * @since SuperWaba 5.5 * @param g The desired Graphics object where to paint. The forecolor must already be set. * @param fmH The fmH member * @param height The height of the control. The check will be vertical aligned based on this height. */ public static void paintCheck(Graphics g, int fmH, int height) // guich@550_29 { if (uiAndroid) try { g.drawImage(Resources.checkSel.getPressedInstance(height,height,0,g.foreColor,true),0,0); } catch (ImageException ie) // just paint something { g.backColor = g.foreColor; g.fillRect(0,0,height,height); } else { int wh = height; int m = 2*wh/5; int yy = m; int xx = 3; wh -= xx; if (fmH <= 10) // guich@tc110_18 { g.backColor = g.foreColor; g.fillRect(2,2,wh+xx-4,wh+xx-4); } else for (int i = xx; i < wh; i++) { g.drawLine(xx, yy, xx, yy + 2); xx++; if (i < m) yy++; else yy--; } } } /** Clears this control, checking it if clearValueInt is 1. */ public void clear() // guich@572_19 { setChecked(clearValueInt == 1); } /** Splits the text to the given width. Remember to set the font (or add the Label to its parent) * before calling this method. * @since TotalCross 1.14 * @see #autoSplit */ public void split(int maxWidth) // guich@tc114_73 { String text = originalText; // originalText will be changed by setText setText(Convert.insertLineBreak(maxWidth, fm, text)); // guich@tc126_18: text cannot be assigned here or originalText will be overwritten originalText = text; } protected void onFontChanged() { int i; if (linesW == null || linesW.length != lines.length) // guich@450_36: avoid keep recreating the int array linesW = new int[lines.length]; int []linesW = this.linesW; // guich@450_36: use local var for (i = lines.length-1; i >= 0; i--) linesW[i] = fm.stringWidth(lines[i]); } protected void onBoundsChanged(boolean screenChanged) { if (autoSplit && this.width > 0 && this.width != lastASW) // guich@tc114_74 - guich@tc120_5: only if PREFERRED was choosen in first setRect - guich@tc126_35 { lastASW = this.width; int wh = lines.length == 1 ? height : fmH+Edit.prefH; split(this.width-wh-2); if (PREFERRED-RANGE <= setH && setH <= PREFERRED+RANGE) setRect(KEEP,KEEP,KEEP,getPreferredHeight() + setH-PREFERRED); } } }