// -*- mode: java; c-basic-offset: 2; -*- // Copyright 2009-2011 Google, All Rights reserved // Copyright 2011-2012 MIT, All rights reserved // Released under the Apache License, Version 2.0 // http://www.apache.org/licenses/LICENSE-2.0 package com.google.appinventor.components.runtime; import com.google.appinventor.components.annotations.DesignerComponent; import com.google.appinventor.components.annotations.DesignerProperty; import com.google.appinventor.components.annotations.PropertyCategory; import com.google.appinventor.components.annotations.SimpleObject; import com.google.appinventor.components.annotations.SimpleProperty; import com.google.appinventor.components.common.ComponentCategory; import com.google.appinventor.components.common.PropertyTypeConstants; import com.google.appinventor.components.common.YaVersion; import com.google.appinventor.components.runtime.util.TextViewUtil; import android.util.Log; import android.view.View; import android.widget.LinearLayout; import android.widget.TextView; /** * Label containing a text string. * */ @DesignerComponent(version = YaVersion.LABEL_COMPONENT_VERSION, description = "A Label displays a piece of text, which is " + "specified through the <code>Text</code> property. Other properties, " + "all of which can be set in the Designer or Blocks Editor, control " + "the appearance and placement of the text.", category = ComponentCategory.USERINTERFACE) @SimpleObject public final class Label extends AndroidViewComponent { // default margin around a label in DPs // note that the spacing between adjacent labels will be twice this value // because each label has a margin private static final int DEFAULT_LABEL_MARGIN = 2; // default margin in density-independent pixels. This must be // computed using the view private int defaultLabelMarginInDp = 0; private final TextView view; private final LinearLayout.LayoutParams linearLayoutParams; // Backing for text alignment private int textAlignment; // Backing for background color private int backgroundColor; // Backing for font typeface private int fontTypeface; // Backing for font bold private boolean bold; // Backing for font italic private boolean italic; // Whether or not the label should have a margin private boolean hasMargins; // Backing for text color private int textColor; // Label Format private boolean htmlFormat; /** * Creates a new Label component. * * @param container container, component will be placed in */ public Label(ComponentContainer container) { super(container); view = new TextView(container.$context()); // Adds the component to its designated container container.$add(this); // Get the layout parameters to use in setting margins (and potentially // other things. // There will be a bug if the label view does not have linear layout params. // TODO(hal): Generalize this for other types of layouts Object lp = view.getLayoutParams(); // The following instanceof check will fail if we have not previously // added the label to the container (Why?) if (lp instanceof LinearLayout.LayoutParams) { linearLayoutParams = (LinearLayout.LayoutParams) lp; defaultLabelMarginInDp = dpToPx(view, DEFAULT_LABEL_MARGIN); } else { defaultLabelMarginInDp = 0; linearLayoutParams = null; Log.e("Label", "Error: The label's view does not have linear layout parameters"); new RuntimeException().printStackTrace(); } // Default property values TextAlignment(Component.ALIGNMENT_NORMAL); BackgroundColor(Component.COLOR_NONE); fontTypeface = Component.TYPEFACE_DEFAULT; TextViewUtil.setFontTypeface(view, fontTypeface, bold, italic); FontSize(Component.FONT_DEFAULT_SIZE); Text(""); TextColor(Component.COLOR_BLACK); HTMLFormat(false); HasMargins(true); } // put this in the right file private static int dpToPx(View view, int dp) { float density = view.getContext().getResources().getDisplayMetrics().density; return Math.round((float)dp * density); } @Override public View getView() { return view; } /** * Returns the alignment of the label's text: center, normal * (e.g., left-justified if text is written left to right), or * opposite (e.g., right-justified if text is written left to right). * * @return one of {@link Component#ALIGNMENT_NORMAL}, * {@link Component#ALIGNMENT_CENTER} or * {@link Component#ALIGNMENT_OPPOSITE} */ @SimpleProperty( category = PropertyCategory.APPEARANCE, userVisible = false) public int TextAlignment() { return textAlignment; } /** * Specifies the alignment of the label's text: center, normal * (e.g., left-justified if text is written left to right), or * opposite (e.g., right-justified if text is written left to right). * * @param alignment one of {@link Component#ALIGNMENT_NORMAL}, * {@link Component#ALIGNMENT_CENTER} or * {@link Component#ALIGNMENT_OPPOSITE} */ @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_TEXTALIGNMENT, defaultValue = Component.ALIGNMENT_NORMAL + "") @SimpleProperty( userVisible = false) public void TextAlignment(int alignment) { this.textAlignment = alignment; TextViewUtil.setAlignment(view, alignment, false); } /** * Returns the label's background color as an alpha-red-green-blue * integer. * * @return background RGB color with alpha */ @SimpleProperty( category = PropertyCategory.APPEARANCE) public int BackgroundColor() { return backgroundColor; } /** * Specifies the label's background color as an alpha-red-green-blue * integer. * * @param argb background RGB color with alpha */ @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_COLOR, defaultValue = Component.DEFAULT_VALUE_COLOR_NONE) @SimpleProperty public void BackgroundColor(int argb) { backgroundColor = argb; if (argb != Component.COLOR_DEFAULT) { TextViewUtil.setBackgroundColor(view, argb); } else { TextViewUtil.setBackgroundColor(view, Component.COLOR_NONE); } } /** * Returns true if the label's text should be bold. * If bold has been requested, this property will return true, even if the * font does not support bold. * * @return {@code true} indicates bold, {@code false} normal */ @SimpleProperty( category = PropertyCategory.APPEARANCE, userVisible = false) public boolean FontBold() { return bold; } /** * Specifies whether the label's text should be bold. * Some fonts do not support bold. * * @param bold {@code true} indicates bold, {@code false} normal */ @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_BOOLEAN, defaultValue = "False") @SimpleProperty( userVisible = false) public void FontBold(boolean bold) { this.bold = bold; TextViewUtil.setFontTypeface(view, fontTypeface, bold, italic); } /** * Returns true if the label's text should be italic. * If italic has been requested, this property will return true, even if the * font does not support italic. * * @return {@code true} indicates italic, {@code false} normal */ @SimpleProperty( category = PropertyCategory.APPEARANCE, userVisible = false) public boolean FontItalic() { return italic; } /** * Specifies whether the label's text should be italic. * Some fonts do not support italic. * * @param italic {@code true} indicates italic, {@code false} normal */ @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_BOOLEAN, defaultValue = "False") @SimpleProperty( userVisible = false) public void FontItalic(boolean italic) { this.italic = italic; TextViewUtil.setFontTypeface(view, fontTypeface, bold, italic); } /** * Returns true if the label should have margins. * * @return {@code true} indicates margins, {@code false} no margins */ @SimpleProperty( category = PropertyCategory.APPEARANCE, description = "Reports whether or not the label appears with margins. All four " + "margins (left, right, top, bottom) are the same. This property has no effect " + "in the designer, where labels are always shown with margins.", userVisible = true) public boolean HasMargins() { return hasMargins; } /** * Specifies whether the label should have margins. * This margin value is not well coordinated with the * designer, where the margins are defined for the arrangement, not just for individual * labels. * * @param hasMargins {@code true} indicates that there are margins, {@code false} no margins */ @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_BOOLEAN, defaultValue = "True") @SimpleProperty( userVisible = true) public void HasMargins(boolean hasMargins) { this.hasMargins = hasMargins; setLabelMargins(hasMargins); } private void setLabelMargins(boolean hasMargins) { int m = hasMargins ? defaultLabelMarginInDp : 0 ; linearLayoutParams.setMargins(m, m, m, m); view.invalidate(); } /** * Returns the label's text's font size, measured in sp(scale-independent pixels). * * @return font size in sp(scale-independent pixels). */ @SimpleProperty( category = PropertyCategory.APPEARANCE) public float FontSize() { return TextViewUtil.getFontSize(view, container.$context()); } /** * Specifies the label's text's font size, measured in sp(scale-independent pixels). * * @param size font size in sp (scale-independent pixels) */ @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_NON_NEGATIVE_FLOAT, defaultValue = Component.FONT_DEFAULT_SIZE + "") @SimpleProperty public void FontSize(float size) { TextViewUtil.setFontSize(view, size); } /** * Returns the label's text's font face as default, serif, sans * serif, or monospace. * * @return one of {@link Component#TYPEFACE_DEFAULT}, * {@link Component#TYPEFACE_SERIF}, * {@link Component#TYPEFACE_SANSSERIF} or * {@link Component#TYPEFACE_MONOSPACE} */ @SimpleProperty( category = PropertyCategory.APPEARANCE, userVisible = false) public int FontTypeface() { return fontTypeface; } /** * Specifies the label's text's font face as default, serif, sans * serif, or monospace. * * @param typeface one of {@link Component#TYPEFACE_DEFAULT}, * {@link Component#TYPEFACE_SERIF}, * {@link Component#TYPEFACE_SANSSERIF} or * {@link Component#TYPEFACE_MONOSPACE} */ @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_TYPEFACE, defaultValue = Component.TYPEFACE_DEFAULT + "") @SimpleProperty( userVisible = false) public void FontTypeface(int typeface) { fontTypeface = typeface; TextViewUtil.setFontTypeface(view, fontTypeface, bold, italic); } /** * Returns the text displayed by the label. * * @return label caption */ @SimpleProperty( category = PropertyCategory.APPEARANCE) public String Text() { return TextViewUtil.getText(view); } /** * Specifies the text displayed by the label. * * @param text new caption for label */ @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_STRING, defaultValue = "") @SimpleProperty public void Text(String text) { if (htmlFormat) { TextViewUtil.setTextHTML(view, text); } else { TextViewUtil.setText(view, text); } } /** * Returns the label's text's format * * @return {@code true} indicates that the label format is html text * {@code false} lines that the label format is plain text */ @SimpleProperty( category = PropertyCategory.APPEARANCE, description = "If true, then this label will show html text else it " + "will show plain text. Note: Not all HTML is supported.") public boolean HTMLFormat() { return htmlFormat; } /** * Specifies the label's text's format * * @return {@code true} indicates that the label format is html text * {@code false} lines that the label format is plain text */ @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_BOOLEAN, defaultValue = "False") @SimpleProperty(userVisible = false) public void HTMLFormat(boolean fmt) { htmlFormat = fmt; if (htmlFormat) { String txt = TextViewUtil.getText(view); TextViewUtil.setTextHTML(view, txt); } else { String txt = TextViewUtil.getText(view); TextViewUtil.setText(view, txt); } } /** * Returns the label's text color as an alpha-red-green-blue * integer. * * @return text RGB color with alpha */ @SimpleProperty( category = PropertyCategory.APPEARANCE) public int TextColor() { return textColor; } /** * Specifies the label's text color as an alpha-red-green-blue * integer. * * @param argb text RGB color with alpha */ @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_COLOR, defaultValue = Component.DEFAULT_VALUE_COLOR_BLACK) @SimpleProperty public void TextColor(int argb) { textColor = argb; if (argb != Component.COLOR_DEFAULT) { TextViewUtil.setTextColor(view, argb); } else { TextViewUtil.setTextColor(view, Component.COLOR_BLACK); } } }