///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2010, Blogagic (http://blogagic.com/)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// - Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
// - Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////////////////////////////
/*
FadingTextInput - TextInput customization.
Version 0.1 - 23/08/2010
FadingTextInput fades background color of the control when it loses focus
while its content has been changed. It also display its border only when
mouse is over the control.
It supports:
- styling options
- enabled and editable states management
- customizable tooltips
- Fade background color effect when changing field
Notes:
Default toolTips are HTML toolTips (refer to http://blogagic.com/190/easy-flex-tooltip-customization-using-html-tags)
Uses the AnimateColor by Darron Schall (refer to http://www.darronschall.com/weblog/2007/01/animate-color-flex-2-effect-updated-for-201.cfm)
Licensed under the Creative Commons BSD Licence (http://creativecommons.org/licenses/BSD/)
*/
package com.blogagic.controls
{
import com.blogagic.core.IDisposable;
import com.darronschall.effects.AnimateColor;
import flash.events.Event;
import flash.events.FocusEvent;
import flash.events.MouseEvent;
import mx.controls.Button;
import mx.controls.TextInput;
import mx.styles.CSSStyleDeclaration;
import mx.styles.StyleManager;
/**
* Color for the field background (target of the fading effect).
*
* Must be used instead of the usual backgroundColor.
* @default #FFFFFF
*/
[Style(name="textBackgroundColor", type="Color", format="Color", inherit="no")]
/**
* Color for the background when leaving the control with a changed text
* (source of the fading effect).
*
* @default #FFFF52
*/
[Style(name="backgroundChangeColor", type="Color", format="Color", inherit="no")]
/**
* Color for the border when hovering over the control.
*
* @default #AAB3B3
*/
[Style(name="borderHoverColor", type="Color", format="Color", inherit="no")]
/**
* The FadingTextInput control is a customized TextInput control.
*
*
FadingTextInput fades background color of the control when it loses focus
* while its content has been changed. It displays its border only when mouse is
* over the control.
* It also automatically selects the TextInput content when clicking on the
* control (TextInput selects the content only when entering the control using
* tab).
*
* @mxml
*
* The <mx:FadingTextInput> tag inherits all the tag attributes
* of its superclass (<mx:TextInput>), and adds the following tag
* attributes:
*
*
* <mx:FadingTextInput
* Properties
* overToolTip="Click to modify field"
* focusTooltip="Enter data"
* notEditableTooltip="Select to scroll or copy text"
* disabledTooltip="This control is disabled."
* allowFadeBackgroundColorEffect="true|false"
* fadeBackgroundColorEffectDuration="1600"
*
* Styles
* textBackgroundColor="0xFFFFFF"
* backgroundChangeColor="0xFFFF52"
* borderHoverColor="0xAAB3B3"
* backgroundColor: do not use it (use textBackgroundColor instead)
* />
*
*
*/
public class FadingTextInput extends TextInput implements IDisposable
{
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
//----------------------------------
// Tooltips
//----------------------------------
/**
* Tooltip displayed when hovering over an editable & enabled control (without the focus).
*
* @default Click to modify
*/
public var overToolTip:String = "Click to modify field";
[Inspectable(category="ToolTip", type="String", defaultValue="Click to modify field")]
/**
* Tooltip displayed when control has focus and is editable.
*
* @default Enter data
*/
public var focusTooltip:String = "Enter data";
[Inspectable(category="ToolTip", type="String", defaultValue="Enter data")]
/**
* Tooltip displayed when control is not editable.
*
* @default Enter data
*/
public var notEditableTooltip:String = "Select to scroll or copy text
This control is not editable.";
[Inspectable(category="ToolTip", type="String", defaultValue="Select to scroll or copy text")]
/**
* Tooltip displayed when control is disabled (enabled=false).
*
* @default This control is disabled
*/
public var disabledTooltip:String = "This control is disabled.";
[Inspectable(category="ToolTip", type="String", defaultValue="This control is disabled.")]
//----------------------------------
// Fade Background Color Effect
//----------------------------------
/**
* @private
* Storage for the Fade Background Color Effect status.
*/
protected var _allowFadeBackgroundColorEffect:Boolean = true;
[Inspectable(category="General", type="Boolean", defaultValue="true")]
/**
* Allows the Fade Background Color effect when field content has been changed
* and focus is lost.
*
* @default true
*/
[Bindable]
public function get allowFadeBackgroundColorEffect():Boolean {
return _allowFadeBackgroundColorEffect;
}
/**
* @private
*/
public function set allowFadeBackgroundColorEffect(value:Boolean):void {
if (value != _allowFadeBackgroundColorEffect) {
_allowFadeBackgroundColorEffect = value;
if (!_allowFadeBackgroundColorEffect && _fadeColorEffect)
_fadeColorEffect.stop();
}
}
/**
* @private
* Storage for the Fade Background Color Effect duration.
*/
protected var _fadeBackgroundColorEffectDuration:Number = 1600;
[Inspectable(category="General", type="Number", defaultValue="1600")]
/**
* Specifies the duration of the Fade Color effect.
*
* @default 1600
*/
[Bindable]
public function get fadeBackgroundColorEffectDuration():Number {
return _fadeBackgroundColorEffectDuration;
}
/**
* @private
* No invalidation, change will take effect next time only.
*/
public function set fadeBackgroundColorEffectDuration(value:Number):void {
if (value != _fadeBackgroundColorEffectDuration) {
_fadeBackgroundColorEffectDuration = value;
if (_fadeColorEffect)
_fadeColorEffect.duration = _fadeBackgroundColorEffectDuration;
}
}
//----------------------------------
// Enabled & Editable
//----------------------------------
/**
* @private
* Combination of editable and enabled.
*/
private var _editAllowed:Boolean = true;
/**
* @private
*/
private var _editAllowedDirty:Boolean = true;
/**
* @private
*/
override public function get enabled():Boolean {
return super.enabled;
}
/**
* @private
*/
override public function set enabled(value:Boolean):void {
if (super.enabled != value) {
super.enabled = value;
_editAllowedDirty = true;
invalidateProperties();
}
}
/**
* @private
*/
private var _editableDirty:Boolean = true;
/**
* @private
*/
override public function get editable():Boolean {
return super.editable;
}
/**
* @private
*/
override public function set editable(value:Boolean):void {
if (super.editable != value) {
super.editable = value;
_editAllowedDirty = true;
invalidateProperties();
}
}
//--------------------------------------------------------------------------
//
// Cleanup
//
//--------------------------------------------------------------------------
/**
* Use the dispose method to explicitly release unmanaged resources in conjunction
* with the garbage collector.
* Call this method when the control is no longer needed.
*
*/
public function dispose():void {
removeEventHandlers();
if (stage)
removeEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler);
else
removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
if (_fadeColorEffect) {
_fadeColorEffect.stop();
_fadeColorEffect = null;
}
}
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
/**
* Constructor.
*/
public function FadingTextInput()
{
super();
addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
}
//--------------------------------------------------------------------------
//
// Styles
//
//--------------------------------------------------------------------------
/**
* @private
*/
private static var classConstructed:Boolean = classConstruct();
/**
* @private
* Styles initialization.
*/
private static function classConstruct():Boolean {
var style:CSSStyleDeclaration = StyleManager.getStyleDeclaration("FadingTextInput");
if (!style) {
style = new CSSStyleDeclaration();
style.defaultFactory = function():void {
this.textBackgroundColor = 0xFFFFFF;
this.borderHoverColor = 0xAAB3B3;
this.backgroundChangeColor = 0xFFFF52;
this.borderStyle = "solid";
};
StyleManager.setStyleDeclaration("FadingTextInput", style, true);
}
else {
if (style.getStyle("textBackgroundColor") == undefined) {
style.setStyle("textBackgroundColor", "0xFFFFFF");
}
if (style.getStyle("borderHoverColor") == undefined) {
style.setStyle("borderHoverColor", "0xAAB3B3");
}
if (style.getStyle("backgroundChangeColor") == undefined) {
style.setStyle("backgroundChangeColor", "0xFFFF52");
}
//if (style.getStyle("borderStyle") == undefined) {
style.setStyle("borderStyle", "solid");
//}
}
return true;
}
/**
* @private
*/
override public function styleChanged(styleProp:String):void {
super.styleChanged(styleProp);
switch (styleProp) {
case "borderHoverColor":
_drawBorderDirty = true;
invalidateProperties();
break;
case "backgroundChangeColor":
if (_fadeColorEffect)
_fadeColorEffect.fromValue = getStyle("backgroundChangeColor");
break;
case "textBackgroundColor":
if (_fadeColorEffect)
_fadeColorEffect.toValue = getStyle("textBackgroundColor");
_textBackgroundColorDirty = true;
invalidateProperties();
break;
}
}
//--------------------------------------------------------------------------
//
// Variables
//
//--------------------------------------------------------------------------
/**
* @private
*/
private var _toolTipDirty:Boolean = true;
/**
* @private
* Indicates if the border must be drawn.
*/
private var _drawBorder:Boolean = false;
/**
* @private
*/
private var _drawBorderDirty:Boolean = true;
/**
* @private
*/
private function get drawBorder():Boolean {
return _drawBorder;
}
/**
* @private
*/
private function set drawBorder(value:Boolean):void {
if (value != _drawBorder) {
_drawBorder = value;
_drawBorderDirty = true;
invalidateProperties();
}
}
/**
* @private
*/
private var _textBackgroundColorDirty:Boolean = true;
/**
* @private
* Indicates if the mouse is over the control.
*/
private var _mouseOver:Boolean = false;
/**
* @private
* Indicates if the control has the focus.
*/
private var _hasFocus:Boolean = false;
/**
* @private
* Control content before editing.
*/
private var _previousText:String;
/**
* @private
* Effect based on AnimateColor class made by Darron Schall
* Note: This is now natively available in Flex 4.
*/
private var _fadeColorEffect:AnimateColor;
//--------------------------------------------------------------------------
//
// Component Life Cycle
//
//--------------------------------------------------------------------------
/**
* @private
*/
override protected function commitProperties():void {
super.commitProperties();
if (_editAllowedDirty) {
_editAllowed = enabled && editable;
_drawBorderDirty = true;
_toolTipDirty = true;
_editAllowedDirty = false;
}
// Text background color has changed, update control background,
// border and color animation effect
if (_textBackgroundColorDirty) {
var style:*;
style = getStyle("textBackgroundColor");
setStyle("backgroundColor", style);
if (!drawBorder)
_drawBorderDirty = true;
if (_fadeColorEffect)
_fadeColorEffect.toValue = style;
_textBackgroundColorDirty = false;
}
// Border visibility has changed, update border color accordingly
if (_drawBorderDirty) {
if (drawBorder && _editAllowed) {
setStyle("borderColor", getStyle("borderHoverColor"));
}
else {
// "Hide" border by using the same color as the control background
// TODO: does not work for border styles inset and outset!
setStyle("borderColor", getStyle("textBackgroundColor"));
}
_drawBorderDirty = false;
}
if (_toolTipDirty) {
manageToolTip();
_toolTipDirty = false;
}
}
//--------------------------------------------------------------------------
//
// Event Listeners management
//
// Event listeners are kept active only when control is on stage.
//--------------------------------------------------------------------------
/**
* @private
*/
private function addedToStageHandler(event:Event): void {
removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
addEventHandlers();
addEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler);
}
/**
* @private
*/
private function removedFromStageHandler(event:Event): void {
removeEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler);
removeEventHandlers();
addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
}
/**
* @private
*/
private function addEventHandlers():void {
addEventListener(MouseEvent.ROLL_OVER, rollOverHandler);
addEventListener(MouseEvent.ROLL_OUT, rollOutHandler);
}
/**
* @private
*/
private function removeEventHandlers():void {
removeEventListener(MouseEvent.ROLL_OVER, rollOverHandler);
removeEventListener(MouseEvent.ROLL_OUT, rollOutHandler);
}
//--------------------------------------------------------------------------
//
// Handlers
//
//--------------------------------------------------------------------------
/**
* @private
* Control got focus:
* - update tooltip
* - keep a copy of text content
* - automatically select text content
*/
override protected function focusInHandler(event:FocusEvent):void {
super.focusInHandler(event);
_hasFocus = true;
if (editable) {
_previousText = textField.text;
drawBorder = false;
setSelection(0, textField.text.length);
}
_toolTipDirty = true;
invalidateProperties();
}
/**
* @private
* Control lost focus:
* - update tooltip
* - trigger a background color animation if text has changed
* - scroll the field to display the beginning of the entered text
*/
override protected function focusOutHandler(event:FocusEvent):void {
super.focusOutHandler(event);
_hasFocus = false;
if (editable) {
_toolTipDirty = true;
invalidateProperties();
// Keep border and clear button visible if mouse is still over the control
if (_mouseOver)
drawBorder = true;
// Fade background color after the change
if (_previousText != textField.text) {
if (allowFadeBackgroundColorEffect) {
createFadeColorEffect();
_fadeColorEffect.end();
_fadeColorEffect.play();
}
}
// When text is too long for being entirely displayed,
// scroll back to the beginning of the text
horizontalScrollPosition = 0;
}
_toolTipDirty = true;
invalidateProperties();
}
/**
* @private
* Update tooltip, show border based on control states
*/
protected function rollOverHandler(event:MouseEvent):void {
if (!_mouseOver) {
_mouseOver = true;
if (!_hasFocus) {
drawBorder = true;
if (_editAllowed) {
_toolTipDirty = true;
invalidateProperties();
}
}
}
}
/**
* @private
* Update tooltip, hide border based on focus
*/
protected function rollOutHandler(event:MouseEvent):void {
if (_mouseOver) {
_mouseOver = false;
if (!_hasFocus) {
drawBorder = false;
}
}
}
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
/**
* @private
* Assign the right ToolTip based on current states.
*/
protected function manageToolTip():void {
if (!enabled)
toolTip = disabledTooltip;
else if (!editable)
toolTip = notEditableTooltip;
else if (_hasFocus)
toolTip = focusTooltip;
else
toolTip = overToolTip;
}
/**
* @private
* Effect based on AnimateColor class made by Darron Schall.
* Note: This effect is now natively available in Flex 4.
*/
protected function createFadeColorEffect():void {
if (!_fadeColorEffect) {
_fadeColorEffect = new AnimateColor(this);
_fadeColorEffect.property = "backgroundColor";
_fadeColorEffect.isStyle = true;
_fadeColorEffect.fromValue = getStyle("backgroundChangeColor");
_fadeColorEffect.toValue = getStyle("textBackgroundColor");
_fadeColorEffect.duration = _fadeBackgroundColorEffectDuration;
}
}
}
}