/* * $Id$ */ /* * Harbour Project source code: * Get Class * * Copyright 1999 Ignacio Ortiz de ZŁniga * www - http://www.harbour-project.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). * * As a special exception, the Harbour Project gives permission for * additional uses of the text contained in its release of Harbour. * * The exception is that, if you link the Harbour libraries with other * files to produce an executable, this does not by itself cause the * resulting executable to be covered by the GNU General Public License. * Your use of that executable is in no way restricted on account of * linking the Harbour library code into it. * * This exception does not however invalidate any other reasons why * the executable file might be covered by the GNU General Public License. * * This exception applies only to the code released by the Harbour * Project under the name Harbour. If you copy code from other * Harbour Project or Free Software Foundation releases into a copy of * Harbour, as the General Public License permits, the exception does * not apply to the code that you add in this way. To avoid misleading * anyone as to the status of such modified files, you must delete * this exception notice from them. * * If you write modifications of your own for Harbour, it is your choice * whether to permit this exception to apply to your modifications. * If you do not wish that, delete this exception notice. * */ /* * The following parts are Copyright of the individual authors. * www - http://www.harbour-project.org * * Copyright 2007 Viktor Szakats * Several smaller methods and lots of fixes using * regression/unit testing. * * See doc/license.txt for licensing terms. * */ #include "hbclass.ch" #include "hblang.ch" #include "color.ch" #include "common.ch" #include "setcurs.ch" #include "getexit.ch" #include "inkey.ch" #include "button.ch" /* TOFIX: ::Minus [vszakats] */ #define GET_CLR_UNSELECTED 0 #define GET_CLR_ENHANCED 1 #define GET_CLR_CAPTION 2 #define GET_CLR_ACCEL 3 /* NOTE: In CA-Cl*pper TGET class does not inherit from any other classes and there is no public class function like Get(). There is in XPP though. */ #if defined(HB_C52_STRICT) && !defined(HB_COMPAT_XPP) CREATE CLASS Get STATIC #else CREATE CLASS Get #endif EXPORT: VAR cargo VAR decPos INIT 0 READONLY /* ; CA-Cl*pper NG says that it contains NIL, but in fact it contains zero. [vszakats] */ VAR exitState VAR hasFocus INIT .F. READONLY VAR original READONLY VAR postBlock VAR preBlock VAR reader VAR rejected INIT .F. READONLY VAR subScript VAR typeOut INIT .F. READONLY METHOD New( nRow, nCol, bVarBlock, cVarName, cPicture, cColorSpec ) /* NOTE: This method is a Harbour extension [vszakats] */ METHOD assign() METHOD badDate() METHOD block( bBlock ) SETGET METHOD buffer( cBuffer ) SETGET METHOD changed( lChanged ) SETGET METHOD clear( lClear ) SETGET METHOD col( nCol ) SETGET METHOD colorDisp( cColorSpec ) METHOD colorSpec( cColorSpec ) SETGET METHOD display( lForced ) /* NOTE: lForced is an undocumented Harbour parameter. Should not be used by app code. [vszakats] */ #ifdef HB_COMPAT_C53 METHOD hitTest( nMRow, nMCol ) METHOD control( oControl ) SETGET /* NOTE: Undocumented CA-Cl*pper 5.3 method. */ METHOD message( cMessage ) SETGET /* NOTE: Undocumented CA-Cl*pper 5.3 method. */ METHOD caption( cCaption ) SETGET /* NOTE: Undocumented CA-Cl*pper 5.3 method. */ METHOD capRow( nCapRow ) SETGET /* NOTE: Undocumented CA-Cl*pper 5.3 method. */ METHOD capCol( nCapCol ) SETGET /* NOTE: Undocumented CA-Cl*pper 5.3 method. */ #endif METHOD killFocus() METHOD minus( lMinus ) SETGET METHOD name( cName ) SETGET METHOD picture( cPicture ) SETGET METHOD pos( nPos ) SETGET #ifdef HB_COMPAT_XPP METHOD posInBuffer( nRow, nCol ) #endif #ifdef HB_C52_UNDOC METHOD reform() #endif METHOD reset() METHOD row( nRow ) SETGET METHOD setFocus() METHOD type() METHOD undo() METHOD unTransform() METHOD updateBuffer() METHOD varGet() METHOD varPut( xValue, lReFormat ) /* NOTE: lReFormat is an undocumented Harbour parameter. Should not be used by app code. [vszakats] */ METHOD end() METHOD home() METHOD left() METHOD right() METHOD toDecPos() METHOD wordLeft() METHOD wordRight() METHOD backSpace( lDisplay ) /* NOTE: lDisplay is an undocumented Harbour parameter. Should not be used by app code. [vszakats] */ METHOD delete( lDisplay ) /* NOTE: lDisplay is an undocumented Harbour parameter. Should not be used by app code. [vszakats] */ METHOD delEnd() METHOD delLeft() METHOD delRight() METHOD delWordLeft() METHOD delWordRight() METHOD insert( cChar ) METHOD overStrike( cChar ) #ifdef HB_EXTENSION METHOD hideInput( lHideInput ) SETGET METHOD style( cStyle ) SETGET #endif #ifdef HB_COMPAT_XPP MESSAGE _end() METHOD end() MESSAGE _assign() METHOD assign() MESSAGE _delete() METHOD delete() #endif PROTECTED: VAR cColorSpec VAR cPicture VAR bBlock VAR cType VAR nPos INIT 0 VAR lChanged INIT .F. VAR lClear INIT .F. VAR nRow VAR nCol VAR cName VAR lRejected INIT .F. VAR cBuffer VAR lHideInput INIT .F. VAR cStyle INIT "*" /* NOTE: First char is to be used as mask character when :hideInput is .T. [vszakats] */ VAR oControl VAR cMessage INIT "" VAR cCaption INIT "" VAR nCapRow INIT 0 VAR nCapCol INIT 0 VAR cPicMask INIT "" VAR cPicFunc INIT "" VAR nMaxLen VAR lEdit INIT .F. VAR lDecRev INIT .F. VAR lPicComplex INIT .F. VAR nDispLen VAR nDispPos INIT 1 VAR nOldPos INIT 0 VAR lCleanZero INIT .F. VAR nMaxEdit VAR lMinus INIT .F. VAR lMinus2 INIT .F. VAR lMinusPrinted INIT .F. VAR xVarGet METHOD DeleteAll() METHOD IsEditable( nPos ) METHOD Input( cChar ) METHOD PutMask( xValue, lEdit ) METHOD FirstEditable() METHOD LastEditable() METHOD ResetPar() ENDCLASS METHOD assign() CLASS Get if ::hasFocus ::VarPut( ::UnTransform(), .F. ) endif return Self METHOD updateBuffer() CLASS Get if ::hasFocus ::cBuffer := ::PutMask( ::VarGet() ) ::Display() else ::VarGet() endif return Self METHOD display( lForced ) CLASS Get local nOldCursor := SetCursor( SC_NONE ) local cBuffer local nDispPos local cCaption local nPos DEFAULT lForced TO .T. if ! ISCHARACTER( ::cBuffer ) ::cType := ValType( ::xVarGet ) ::picture := ::cPicture endif if ::hasFocus cBuffer := ::cBuffer else cBuffer := ::PutMask( ::VarGet() ) endif if ::nMaxLen == NIL ::nMaxLen := Len( cBuffer ) endif if ::nDispLen == NIL ::nDispLen := ::nMaxLen endif if ::cType == "N" .and. ::hasFocus .and. ! ::lMinusPrinted .and. ; ::decPos != 0 .and. ::lMinus2 .and. ; ::nPos > ::decPos .and. Val( Left( cBuffer, ::decPos - 1 ) ) == 0 // display "-." only in case when value on the left side of // the decimal point is equal 0 cBuffer := SubStr( cBuffer, 1, ::decPos - 2 ) + "-." + SubStr( cBuffer, ::decPos + 1 ) endif if ::nDispLen != ::nMaxLen .and. ::nPos != 0 // ; has scroll? if ::nDispLen > 8 nDispPos := Max( 1, Min( ::nPos - ::nDispLen + 4 , ::nMaxLen - ::nDispLen + 1 ) ) else nDispPos := Max( 1, Min( ::nPos - Int( ::nDispLen / 2 ), ::nMaxLen - ::nDispLen + 1 ) ) endif else nDispPos := 1 endif /* Handle C5.3 caption. */ if !Empty( ::cCaption ) cCaption := ::cCaption if ( nPos := At( "&", cCaption ) ) > 0 if nPos == Len( cCaption ) nPos := 0 else cCaption := Stuff( cCaption, nPos, 1, "" ) endif endif DispOutAt( ::nCapRow, ::nCapCol, cCaption, hb_ColorIndex( ::cColorSpec, GET_CLR_CAPTION ) ) if nPos > 0 DispOutAt( ::nCapRow, ::nCapCol + nPos - 1, SubStr( cCaption, nPos, 1 ), hb_ColorIndex( ::cColorSpec, GET_CLR_ACCEL ) ) endif endif /* Display the GET */ if cBuffer != NIL .and. ( lForced .or. nDispPos != ::nOldPos ) DispOutAt( ::nRow, ::nCol,; iif( ::lHideInput, PadR( Replicate( SubStr( ::cStyle, 1, 1 ), Len( RTrim( cBuffer ) ) ), ::nDispLen ), SubStr( cBuffer, nDispPos, ::nDispLen ) ),; hb_ColorIndex( ::cColorSpec, iif( ::hasFocus, GET_CLR_ENHANCED, GET_CLR_UNSELECTED ) ) ) if Set( _SET_DELIMITERS ) .AND. !::hasFocus DispOutAt( ::nRow, ::nCol - 1, SubStr( Set( _SET_DELIMCHARS ), 1, 1 ) ) DispOutAt( ::nRow, ::nCol + ::nDispLen, SubStr( Set( _SET_DELIMCHARS ), 2, 1 ) ) endif endif if ::nPos != 0 SetPos( ::nRow, ::nCol + ::nPos - nDispPos ) endif ::nOldPos := nDispPos SetCursor( nOldCursor ) return Self /* ------------------------------------------------------------------------- */ METHOD colorDisp( cColorSpec ) CLASS Get ::ColorSpec( cColorSpec ) ::Display() return Self METHOD end() CLASS Get local nLastCharPos local nPos local nFor if ::hasFocus nLastCharPos := Min( Len( RTrim( ::cBuffer ) ) + 1, ::nMaxEdit ) if ::nPos != nLastCharPos nPos := nLastCharPos else nPos := ::nMaxEdit endif for nFor := nPos to ::FirstEditable() step -1 if ::IsEditable( nFor ) ::Pos := nFor exit endif next ::lClear := .F. ::typeOut := ( ::nPos == 0 ) ::Display( .F. ) endif return Self METHOD home() CLASS Get if ::hasFocus ::Pos := ::FirstEditable() ::lClear := .F. ::typeOut := ( ::nPos == 0 ) ::Display( .F. ) endif return Self METHOD reset() CLASS Get if ::hasFocus ::cBuffer := ::PutMask( ::VarGet(), .F. ) ::Pos := ::FirstEditable() /* ; Simple 0 in CA-Cl*pper [vszakats] */ ::lClear := ( "K" $ ::cPicFunc .or. ::cType == "N" ) ::lEdit := .F. ::lMinus := .F. ::rejected := .F. ::typeOut := !( ::Type $ "CNDL" ) .or. ( ::nPos == 0 ) /* ; Simple .F. in CA-Cl*pper [vszakats] */ ::Display() endif return Self METHOD undo() CLASS Get if ::hasFocus ::VarPut( ::original ) ::Reset() ::lChanged := .F. endif return Self METHOD setFocus() CLASS Get local xVarGet if ::hasFocus return Self endif xVarGet := ::VarGet() ::hasFocus := .T. ::rejected := .F. ::original := xVarGet ::cType := ValType( xVarGet ) ::Picture := ::cPicture ::cBuffer := ::PutMask( xVarGet, .F. ) ::ResetPar() ::lChanged := .F. ::lClear := ( "K" $ ::cPicFunc .or. ::cType == "N" ) ::lEdit := .F. ::Pos := 1 ::lMinusPrinted := .F. ::lMinus := .F. ::Display() return Self METHOD killFocus() CLASS Get local lHadFocus if ::lEdit ::Assign() endif lHadFocus := ::hasFocus ::hasFocus := .F. ::nPos := 0 ::lClear := .F. ::lMinus := .F. ::lChanged := .F. ::decPos := 0 /* ; CA-Cl*pper NG says that it contains NIL, but in fact it contains zero. [vszakats] */ ::typeOut := .F. if lHadFocus ::Display() endif ::xVarGet := NIL ::original := NIL ::cBuffer := NIL return Self METHOD varPut( xValue, lReFormat ) CLASS Get local aSubs local nLen local aValue local i if ISBLOCK( ::bBlock ) aSubs := ::subScript if ISARRAY( aSubs ) .and. ! Empty( aSubs ) nLen := Len( aSubs ) aValue := Eval( ::bBlock ) for i := 1 to nLen - 1 if ISNUMBER( aSubs[ i ] ) aValue := aValue[ aSubs[ i ] ] else exit endif next if ISNUMBER( aSubs[ i ] ) aValue[ aSubs[ i ] ] := xValue endif else Eval( ::bBlock, xValue ) endif DEFAULT lReFormat TO .T. if lReFormat ::cType := ValType( xValue ) ::xVarGet := xValue ::lEdit := .F. ::Picture := ::cPicture ::nDispLen := NIL endif else xValue := NIL endif return xValue METHOD varGet() CLASS Get local aSubs local nLen local i local xValue if ISBLOCK( ::bBlock ) aSubs := ::subScript if ISARRAY( aSubs ) .and. ! Empty( aSubs ) nLen := Len( aSubs ) xValue := Eval( ::bBlock ) for i := 1 to nLen if ISNUMBER( aSubs[ i ] ) xValue := xValue[ aSubs[ i ] ] else exit endif next else xValue := Eval( ::bBlock ) endif else xValue := ::xVarGet endif ::xVarGet := xValue return xValue METHOD unTransform() CLASS Get local cBuffer local xValue local nFor local lMinus if ! ::hasFocus return NIL endif cBuffer := ::cBuffer if ! ISCHARACTER( cBuffer ) ::lClear := .F. ::decPos := 0 ::nPos := 0 ::typeOut := .F. return NIL endif do case case ::cType == "C" if "R" $ ::cPicFunc for nFor := 1 to Len( ::cPicMask ) if !SubStr( ::cPicMask, nFor, 1 ) $ "ANX9#!LY" cBuffer := SubStr( cBuffer, 1, nFor - 1 ) + Chr( 1 ) + SubStr( cBuffer, nFor + 1 ) endif next xValue := PadR( StrTran( cBuffer, Chr( 1 ), "" ), Len( ::original ) ) else xValue := cBuffer endif case ::cType == "N" lMinus := .F. if "X" $ ::cPicFunc if Right( cBuffer, 2 ) == "DB" lMinus := .T. endif endif if !lMinus for nFor := 1 to ::nMaxLen if ::IsEditable( nFor ) .and. IsDigit( SubStr( cBuffer, nFor, 1 ) ) exit endif if SubStr( cBuffer, nFor, 1 ) $ "-(" .and. !( SubStr( cBuffer, nFor, 1 ) == SubStr( ::cPicMask, nFor, 1 ) ) lMinus := .T. exit endif next endif cBuffer := Space( ::FirstEditable() - 1 ) + SubStr( cBuffer, ::FirstEditable(), ::LastEditable() - ::FirstEditable() + 1 ) if "D" $ ::cPicFunc for nFor := ::FirstEditable() to ::LastEditable() if !::IsEditable( nFor ) cBuffer := Left( cBuffer, nFor - 1 ) + Chr( 1 ) + SubStr( cBuffer, nFor + 1 ) endif next else if "E" $ ::cPicFunc .or. ::lDecRev cBuffer := Left( cBuffer, ::FirstEditable() - 1 ) +; StrTran( StrTran( SubStr( cBuffer, ::FirstEditable(), ::LastEditable() - ::FirstEditable() + 1 ), ".", " " ), ",", "." ) +; SubStr( cBuffer, ::LastEditable() + 1 ) else cBuffer := Left( cBuffer, ::FirstEditable() - 1 ) +; StrTran( SubStr( cBuffer, ::FirstEditable(), ::LastEditable() - ::FirstEditable() + 1 ), ",", " " ) +; SubStr( cBuffer, ::LastEditable() + 1 ) endif for nFor := ::FirstEditable() to ::LastEditable() if !::IsEditable( nFor ) .and. !( SubStr( cBuffer, nFor, 1 ) == "." ) cBuffer := Left( cBuffer, nFor - 1 ) + Chr( 1 ) + SubStr( cBuffer, nFor + 1 ) endif next endif cBuffer := StrTran( cBuffer, Chr( 1 ), "" ) cBuffer := StrTran( cBuffer, "$", " " ) cBuffer := StrTran( cBuffer, "*", " " ) cBuffer := StrTran( cBuffer, "-", " " ) cBuffer := StrTran( cBuffer, "(", " " ) cBuffer := StrTran( cBuffer, ")", " " ) cBuffer := PadL( StrTran( cBuffer, " ", "" ), Len( cBuffer ) ) if lMinus for nFor := 1 to Len( cBuffer ) if IsDigit( SubStr( cBuffer, nFor, 1 ) ) .or. SubStr( cBuffer, nFor, 1 ) == "." exit endif next nFor-- if nFor > 0 cBuffer := Left( cBuffer, nFor - 1 ) + "-" + SubStr( cBuffer, nFor + 1 ) else cBuffer := "-" + cBuffer endif endif xValue := Val( cBuffer ) case ::cType == "L" cBuffer := Upper( cBuffer ) xValue := "T" $ cBuffer .or. "Y" $ cBuffer .or. hb_LangMessage( HB_LANG_ITEM_BASE_TEXT + 1 ) $ cBuffer case ::cType == "D" if "E" $ ::cPicFunc cBuffer := SubStr( cBuffer, 4, 3 ) + SubStr( cBuffer, 1, 3 ) + SubStr( cBuffer, 7 ) endif xValue := CToD( cBuffer ) endcase return xValue METHOD overStrike( cChar ) CLASS Get if ! ::hasFocus return Self endif if ::cType == "N" .and. ! ::lEdit .and. ::lClear ::Pos := ::FirstEditable() endif if ::Pos > ::nMaxEdit ::rejected := .T. return Self endif cChar := ::Input( cChar ) if cChar == "" ::rejected := .T. return Self else ::rejected := .F. endif if ::lClear .and. ::nPos == ::FirstEditable() ::DeleteAll() ::lClear := .F. endif ::lEdit := .T. if ::nPos == 0 ::Pos := 1 endif do while ! ::IsEditable( ::nPos ) .and. ::nPos <= ::nMaxEdit ::Pos++ enddo if ::nPos > ::nMaxEdit ::Pos := ::FirstEditable() endif ::cBuffer := SubStr( ::cBuffer, 1, ::nPos - 1 ) + cChar + SubStr( ::cBuffer, ::nPos + 1 ) ::lChanged := .T. ::Right( .F. ) ::Display() return Self METHOD insert( cChar ) CLASS Get local n local nMaxEdit if ! ::hasFocus return Self endif nMaxEdit := ::nMaxEdit if ::cType == "N" .and. ! ::lEdit .and. ::lClear ::Pos := ::FirstEditable() endif if ::nPos > ::nMaxEdit ::rejected := .T. return Self endif cChar := ::Input( cChar ) if cChar == "" ::rejected := .T. return Self else ::rejected := .F. endif if ::lClear .and. ::nPos == ::FirstEditable() ::DeleteAll() ::lClear := .F. endif ::lEdit := .T. if ::nPos == 0 ::Pos := 1 endif do while ! ::IsEditable( ::nPos ) .and. ::nPos <= ::nMaxEdit ::Pos++ enddo if ::nPos > ::nMaxEdit ::Pos := ::FirstEditable() endif if ::lPicComplex // Calculating different nMaxEdit for ::lPicComplex for n := ::nPos to nMaxEdit if !::IsEditable( n ) exit endif next nMaxEdit := n ::cBuffer := Left( SubStr( ::cBuffer, 1, ::nPos - 1 ) + cChar +; SubStr( ::cBuffer, ::nPos, nMaxEdit - 1 - ::nPos ) +; SubStr( ::cBuffer, nMaxEdit ), ::nMaxLen ) else ::cBuffer := Left( SubStr( ::cBuffer, 1, ::nPos - 1 ) + cChar + SubStr( ::cBuffer, ::nPos ), ::nMaxEdit ) endif ::lChanged := .T. ::Right( .F. ) ::Display() return Self METHOD right( lDisplay ) CLASS Get local nPos if ! ::hasFocus return Self endif DEFAULT lDisplay TO .T. ::typeOut := .F. ::lClear := .F. if ::nPos == ::nMaxEdit ::typeOut := .T. return Self endif nPos := ::nPos + 1 do while ! ::IsEditable( nPos ) .and. nPos <= ::nMaxEdit nPos++ enddo if nPos <= ::nMaxEdit ::Pos := nPos else ::typeOut := .T. endif if lDisplay ::Display( .F. ) endif return Self METHOD left( lDisplay ) CLASS Get local nPos if ! ::hasFocus return Self endif DEFAULT lDisplay TO .T. ::typeOut := .F. ::lClear := .F. if ::nPos == ::FirstEditable() ::typeOut := .T. return Self endif nPos := ::nPos - 1 do while ! ::IsEditable( nPos ) .and. nPos > 0 nPos-- enddo if nPos > 0 ::Pos := nPos else ::typeOut := .T. endif if lDisplay ::Display( .F. ) endif return Self METHOD wordLeft() CLASS Get local nPos if ! ::hasFocus return Self endif ::typeOut := .F. ::lClear := .F. if ::nPos == ::FirstEditable() ::typeOut := .T. return Self endif nPos := ::nPos - 1 do while nPos > 0 if SubStr( ::cBuffer, nPos, 1 ) == " " do while nPos > 0 .and. SubStr( ::cBuffer, nPos, 1 ) == " " nPos-- enddo do while nPos > 0 .and. !( SubStr( ::cBuffer, nPos, 1 ) == " " ) nPos-- enddo if nPos > 0 nPos++ endif exit endif nPos-- enddo if nPos < 1 nPos := 1 endif if nPos > 0 ::Pos := nPos endif ::Display( .F. ) return Self METHOD wordRight() CLASS Get local nPos if ! ::hasFocus return Self endif ::typeOut := .F. ::lClear := .F. if ::nPos == ::nMaxEdit ::typeOut := .T. return Self endif nPos := ::nPos + 1 do while nPos <= ::nMaxEdit if SubStr( ::cBuffer, nPos, 1 ) == " " do while nPos <= ::nMaxEdit .and. SubStr( ::cBuffer, nPos, 1 ) == " " nPos++ enddo exit endif nPos++ enddo if nPos > ::nMaxEdit nPos := ::nMaxEdit endif if nPos <= ::nMaxEdit ::Pos := nPos endif ::Display( .F. ) return Self METHOD toDecPos() CLASS Get if ::hasFocus if ::lClear ::DelEnd() endif ::cBuffer := ::PutMask( ::UnTransform(), .F. ) ::Pos := ::decPos ::lChanged := .T. if ::UnTransform() == 0 .and. ::lMinus ::Backspace() ::Overstrike("-") endif ::Display() endif return Self METHOD backSpace( lDisplay ) CLASS Get local nPos local nMinus if ! ::hasFocus return Self endif nPos := ::nPos DEFAULT lDisplay TO .T. if nPos > 1 .and. nPos == ::FirstEditable() .and. ::lMinus2 /* To delete the parenthesis (negative indicator) in a non editable position */ nMinus := At( "(", SubStr( ::cBuffer, 1, nPos-1 ) ) if nMinus > 0 .and. !( SubStr( ::cPicMask, nMinus, 1 ) == "(" ) ::lEdit := .T. ::cBuffer := SubStr( ::cBuffer, 1, nMinus - 1 ) + " " +; SubStr( ::cBuffer, nMinus + 1 ) ::lChanged := .T. if lDisplay ::Display() endif return Self endif endif ::Left() if ::nPos < nPos ::Delete( lDisplay ) endif return Self METHOD delete( lDisplay ) CLASS Get local nMaxLen local n if ! ::hasFocus return Self endif nMaxLen := ::nMaxLen DEFAULT lDisplay TO .T. ::lClear := .F. ::lEdit := .T. if ::lPicComplex // Calculating different nMaxLen for ::lPicComplex for n := ::nPos to nMaxLen if !::IsEditable( n ) exit endif next nMaxLen := n - 1 endif if ::cType == "N" .and. SubStr( ::cBuffer, ::nPos, 1 ) $ "(-" ::lMinus2 := .F. endif ::cBuffer := PadR( SubStr( ::cBuffer, 1, ::nPos - 1 ) + ; SubStr( ::cBuffer, ::nPos + 1, nMaxLen - ::nPos ) + " " +; SubStr( ::cBuffer, nMaxLen + 1 ), ::nMaxLen ) ::lChanged := .T. if lDisplay ::Display() endif return Self METHOD delEnd() CLASS Get local nPos if ! ::hasFocus return Self endif nPos := ::nPos ::Pos := ::nMaxEdit ::Delete( .F. ) do while ::nPos > nPos ::BackSpace( .F. ) enddo ::Display() return Self METHOD delLeft() CLASS Get ::Left( .F. ) ::Delete( .F. ) ::Right() return Self METHOD delRight() CLASS Get ::Right( .F. ) ::Delete( .F. ) ::Left() return Self /* NOTE ::WordLeft() ::DelWordRight() */ METHOD delWordLeft() CLASS Get if ! ::hasFocus return Self endif if !( SubStr( ::cBuffer, ::nPos, 1 ) == " " ) if SubStr( ::cBuffer, ::nPos - 1, 1 ) == " " ::BackSpace( .F. ) else ::WordRight() ::Left() endif endif if SubStr( ::cBuffer, ::nPos, 1 ) == " " ::Delete( .F. ) endif do while ::nPos > 1 .and. !( SubStr( ::cBuffer, ::nPos - 1, 1 ) == " " ) ::BackSpace( .F. ) enddo ::Display() return Self METHOD delWordRight() CLASS Get if ! ::hasFocus return Self endif ::typeOut := .F. ::lClear := .F. if ::nPos == ::nMaxEdit ::typeOut := .T. return Self endif do while ::nPos <= ::nMaxEdit .and. !( SubStr( ::cBuffer, ::nPos, 1 ) == " " ) ::Delete( .F. ) enddo if ::nPos <= ::nMaxEdit ::Delete( .F. ) endif ::Display() return Self /* The METHOD ColorSpec and VAR cColorSpec allow to replace the * property ColorSpec for a function to control the content and * to carry out certain actions to normalize the data. * The particular case is that the function receives a single color and * be used for GET_CLR_UNSELECTED and GET_CLR_ENHANCED. */ METHOD colorSpec( cColorSpec ) CLASS Get local nClrUns local nClrOth local cClrOth if PCount() == 0 return ::cColorSpec endif if ISCHARACTER( cColorSpec ) #ifdef HB_COMPAT_C53 ::cColorSpec := hb_NToColor( nClrUns := hb_ColorToN( hb_ColorIndex( cColorSpec, GET_CLR_UNSELECTED ) ) ) +; "," + hb_NToColor( iif( ( nClrOth := hb_ColorToN( cClrOth := hb_ColorIndex( cColorSpec, GET_CLR_ENHANCED ) ) ) != 0 .or. Upper( StrTran( cClrOth, " ", "" ) ) == "N/N", nClrOth, nClrUns ) ) +; "," + hb_NToColor( iif( ( nClrOth := hb_ColorToN( cClrOth := hb_ColorIndex( cColorSpec, GET_CLR_CAPTION ) ) ) != 0 .or. Upper( StrTran( cClrOth, " ", "" ) ) == "N/N", nClrOth, nClrUns ) ) +; "," + hb_NToColor( iif( ( nClrOth := hb_ColorToN( cClrOth := hb_ColorIndex( cColorSpec, GET_CLR_ACCEL ) ) ) != 0 .or. Upper( StrTran( cClrOth, " ", "" ) ) == "N/N", nClrOth, nClrUns ) ) #else ::cColorSpec := hb_NToColor( nClrUns := hb_ColorToN( hb_ColorIndex( cColorSpec, GET_CLR_UNSELECTED ) ) ) +; "," + hb_NToColor( iif( ( nClrOth := hb_ColorToN( cClrOth := hb_ColorIndex( cColorSpec, GET_CLR_ENHANCED ) ) ) != 0 .or. Upper( StrTran( cClrOth, " ", "" ) ) == "N/N", nClrOth, nClrUns ) ) #endif return cColorSpec endif return iif( ValType( cColorSpec ) $ "UNDBA", NIL, cColorSpec ) /* ; CA-Cl*pper oddity [vszakats] */ METHOD pos( nPos ) CLASS Get local tmp if PCount() == 0 return ::nPos endif if ISNUMBER( nPos ) if ::hasFocus do case case nPos > ::nMaxLen if ::nMaxLen == 0 ::nPos := 1 else ::nPos := ::nMaxLen endif ::typeOut := .T. case nPos > 0 /* NOTE: CA-Cl*pper has a bug where negative nPos value will be translated to 16bit unsigned int, so the behaviour will be different in this case. [vszakats] */ for tmp := nPos to ::nMaxLen if ::IsEditable( tmp ) ::nPos := tmp return nPos endif next for tmp := nPos - 1 to 1 step -1 if ::IsEditable( tmp ) ::nPos := tmp return nPos endif next ::nPos := ::nMaxLen + 1 ::typeOut := .T. endcase endif return nPos endif return 0 /* The METHOD Picture and VAR cPicture allow to replace the * property Picture for a function to control the content and * to carry out certain actions to normalize the data. * The particular case is that the Picture is loaded later on * to the creation of the object, being necessary to carry out * several tasks to adjust the internal data of the object. */ METHOD picture( cPicture ) CLASS Get local cChar local nAt local nFor local cNum if PCount() == 0 return ::cPicture endif if cPicture != NIL ::cPicture := cPicture ::cPicFunc := "" ::cPicMask := "" ::lPicComplex := .F. IF ISCHARACTER( cPicture ) ::nDispLen := NIL cNum := "" if Left( cPicture, 1 ) == "@" nAt := At( " ", cPicture ) if nAt == 0 ::cPicFunc := Upper( cPicture ) ::cPicMask := "" else ::cPicFunc := Upper( SubStr( cPicture, 1, nAt - 1 ) ) ::cPicMask := SubStr( cPicture, nAt + 1 ) endif if "D" $ ::cPicFunc ::cPicMask := Set( _SET_DATEFORMAT ) ::cPicMask := StrTran( ::cPicmask, "y", "9" ) ::cPicMask := StrTran( ::cPicmask, "Y", "9" ) ::cPicMask := StrTran( ::cPicmask, "m", "9" ) ::cPicMask := StrTran( ::cPicmask, "M", "9" ) ::cPicMask := StrTran( ::cPicmask, "d", "9" ) ::cPicMask := StrTran( ::cPicmask, "D", "9" ) endif if ( nAt := At( "S", ::cPicFunc ) ) > 0 for nFor := nAt + 1 to Len( ::cPicFunc ) if ! IsDigit( SubStr( ::cPicFunc, nFor, 1 ) ) exit else cNum += SubStr( ::cPicFunc, nFor, 1 ) endif next if Val( cNum ) > 0 ::nDispLen := Val( cNum ) endif ::cPicFunc := SubStr( ::cPicFunc, 1, nAt - 1 ) + SubStr( ::cPicFunc, nFor ) endif if "Z" $ ::cPicFunc ::lCleanZero := .T. else ::lCleanZero := .F. endif ::cPicFunc := StrTran( ::cPicFunc, "Z", "" ) if ::cPicFunc == "@" ::cPicFunc := "" endif else ::cPicFunc := "" ::cPicMask := cPicture ::lCleanZero := .F. endif // if ::cType == NIL // ::original := ::xVarGet // ::cType := ValType( ::original ) // endif if ::cType == "D" ::cPicMask := LTrim( ::cPicMask ) endif // Comprobar si tiene la , y el . cambiado (Solo en Xbase++) ::lDecRev := "," $ Transform( 1.1, "9.9" ) endif endif // Generate default picture mask if not specified if Empty( ::cPicMask ) .or. ::cPicture == NIL do case case ::cType == "D" ::cPicMask := Set( _SET_DATEFORMAT ) ::cPicMask := StrTran( ::cPicmask, "y", "9" ) ::cPicMask := StrTran( ::cPicmask, "Y", "9" ) ::cPicMask := StrTran( ::cPicmask, "m", "9" ) ::cPicMask := StrTran( ::cPicmask, "M", "9" ) ::cPicMask := StrTran( ::cPicmask, "d", "9" ) ::cPicMask := StrTran( ::cPicmask, "D", "9" ) case ::cType == "N" cNum := Str( ::xVarGet ) if ( nAt := At( iif( ::lDecRev, ",", "." ), cNum ) ) > 0 ::cPicMask := Replicate( "9", nAt - 1 ) + iif( ::lDecRev, ",", "." ) ::cPicMask += Replicate( "9", Len( cNum ) - Len( ::cPicMask ) ) else ::cPicMask := Replicate( "9", Len( cNum ) ) endif case ::cType == "C" .and. ::cPicFunc == "@9" ::cPicMask := Replicate( "9", Len( ::xVarGet ) ) ::cPicFunc := "" endcase endif // Comprobar si tiene caracteres embebidos no modificables en la plantilla if ! Empty( ::cPicMask ) for nFor := 1 to Len( ::cPicMask ) cChar := SubStr( ::cPicMask, nFor, 1 ) if !( cChar $ "!ANX9#" ) ::lPicComplex := .T. exit endif next endif return ::cPicture METHOD type() CLASS Get return ::cType := ValType( iif( ::hasFocus, ::xVarGet, ::VarGet() ) ) /* The METHOD Block and VAR bBlock allow to replace the * property Block for a function to control the content and * to carry out certain actions to normalize the data. * The particular case is that the Block is loaded later on * to the creation of the object, being necessary to carry out * several tasks to adjust the internal data of the object * to display correctly. */ METHOD block( bBlock ) CLASS Get if PCount() == 0 .or. bBlock == NIL return ::bBlock endif ::bBlock := bBlock ::xVarGet := ::original ::cType := ValType( ::xVarGet ) return bBlock METHOD firstEditable() CLASS Get local nFor if ::nMaxLen != NIL if ::IsEditable( 1 ) return 1 endif for nFor := 2 to ::nMaxLen if ::IsEditable( nFor ) return nFor endif next endif return 0 METHOD lastEditable() CLASS Get local nFor if ::nMaxLen != NIL for nFor := ::nMaxLen to 1 step -1 if ::IsEditable( nFor ) return nFor endif next endif return 0 METHOD resetPar() CLASS Get ::nMaxLen := Len( ::cBuffer ) if ::nDispLen == NIL ::nDispLen := ::nMaxLen endif if ::cType == "N" ::decPos := At( iif( ::lDecRev .or. "E" $ ::cPicFunc, ",", "." ), ::cBuffer ) if ::decPos == 0 ::decPos := Len( ::cBuffer ) + 1 endif ::lMinus2 := ( ::xVarGet < 0 ) else ::decPos := 0 /* ; CA-Cl*pper NG says that it contains NIL, but in fact it contains zero. [vszakats] */ endif return Self METHOD badDate() CLASS Get local xValue return ::hasFocus .and. ; ::Type == "D" .and. ; ( xValue := ::UnTransform() ) == hb_SToD( "" ) .and. ; !( ::cBuffer == Transform( xValue, ::cPicture ) ) #ifdef HB_C52_UNDOC METHOD reform() CLASS Get if ::hasFocus ::cBuffer := ::PutMask( ::UnTransform(), .F. ) endif return Self #endif #ifdef HB_COMPAT_C53 METHOD hitTest( nMRow, nMCol ) CLASS Get if ISOBJECT( ::oControl ) return ::oControl:hitTest( nMRow, nMCol ) else do case case nMRow == ::nRow .and. ; nMCol >= ::nCol .and. ; nMCol < ::nCol + iif( ::nDispLen == NIL, 0, ::nDispLen ) return HTCLIENT case nMRow == ::nCapRow .and. ; nMCol >= ::nCapCol .and. ; nMCol < ::nCapCol + Len( ::cCaption ) /* NOTE: C5.3 doesn't care about the shortcut key. */ return HTCAPTION endcase endif return HTNOWHERE METHOD control( oControl ) CLASS Get if PCount() == 1 .and. ( oControl == NIL .or. ISOBJECT( oControl ) ) ::oControl := oControl endif return ::oControl METHOD caption( cCaption ) CLASS Get if ISCHARACTER( cCaption ) ::cCaption := cCaption endif return ::cCaption METHOD capRow( nCapRow ) CLASS Get if ISNUMBER( nCapRow ) ::nCapRow := Int( nCapRow ) endif return ::nCapRow METHOD capCol( nCapCol ) CLASS Get if ISNUMBER( nCapCol ) ::nCapCol := Int( nCapCol ) endif return ::nCapCol METHOD message( cMessage ) CLASS Get if ISCHARACTER( cMessage ) ::cMessage := cMessage endif return ::cMessage #endif #ifdef HB_COMPAT_XPP /* NOTE: Not tested or compared to XBase++. [vszakats] */ /* TOFIX: To make it work when @S was used. [vszakats] */ METHOD posInBuffer( nRow, nCol ) CLASS Get if nRow == ::nRow .and. ; nCol >= ::nCol + ::nPos - 1 .and. ; nCol <= ::nCol + ::nDispLen return nCol - ::nCol + 1 endif return 0 #endif /* ------------------------------------------------------------------------- */ METHOD DeleteAll() CLASS Get local xValue if ! ::hasFocus return Self endif ::lEdit := .T. do case case ::cType == "C" xValue := Space( ::nMaxlen ) case ::cType == "N" xValue := 0 ::lMinus2 := .F. case ::cType == "D" xValue := CToD( "" ) case ::cType == "L" xValue := .F. endcase ::cBuffer := ::PutMask( xValue, .T. ) ::Pos := ::FirstEditable() return Self METHOD IsEditable( nPos ) CLASS Get local cChar if Empty( ::cPicMask ) return .T. endif /* ; This odd behaviour helps to be more compatible with CA-Cl*pper in some rare situations. xVar := 98 ; o := _GET_( xVar, "xVar" ) ; o:SetFocus() ; o:picture := "99999" ; o:UnTransform() -> result We're still not 100% compatible in slighly different situations because the CA-Cl*pper behaviour is pretty much undefined here. [vszakats] */ if nPos > Len( ::cPicMask ) .and. nPos <= ::nMaxLen return .T. endif cChar := SubStr( ::cPicMask, nPos, 1 ) do case case ::cType == "C" return cChar $ "!ANX9#LY" case ::cType == "N" return cChar $ "9#$*" case ::cType == "D" return cChar == "9" case ::cType == "L" return cChar $ "LY#" /* CA-Cl*pper 5.2 undocumented: # allow T,F,Y,N for Logical [ckedem] */ endcase return .F. METHOD Input( cChar ) CLASS Get local cPic do case case ::cType == "N" do case case cChar == "-" ::lMinus2 := .T. /* The minus symbol can be written in any place */ ::lMinus := .T. case cChar $ ".," ::toDecPos() return "" case ! ( cChar $ "0123456789+" ) return "" endcase case ::cType == "D" if !( cChar $ "0123456789" ) return "" endif case ::cType == "L" if !( Upper( cChar ) $ "YNTF" ) return "" endif endcase if ! Empty( ::cPicFunc ) cChar := Left( Transform( cChar, ::cPicFunc ), 1 ) // Left needed for @D endif if ! Empty( ::cPicMask ) cPic := SubStr( ::cPicMask, ::nPos, 1 ) // cChar := Transform( cChar, cPic ) // Above line eliminated because some get picture template symbols for // numeric input not work in text input. eg: $ and * do case case cPic == "A" if ! IsAlpha( cChar ) cChar := "" endif case cPic == "N" if ! IsAlpha( cChar ) .and. ! IsDigit( cChar ) cChar := "" endif case cPic == "9" if ! IsDigit( cChar ) .and. ! cChar $ "-+" cChar := "" endif if !( ::cType == "N" ) .and. cChar $ "-+" cChar := "" endif /* Clipper 5.2 undocumented: # allow T,F,Y,N for Logical [ckedem] */ case cPic == "L" .or. ( cPic == "#" .and. ::cType == "L" ) if !( Upper( cChar ) $ "YNTF" + ; hb_langmessage( HB_LANG_ITEM_BASE_TEXT + 1 ) + ; hb_langmessage( HB_LANG_ITEM_BASE_TEXT + 2 ) ) cChar := "" endif case cPic == "#" if ! IsDigit( cChar ) .and. !( cChar == " " ) .and. !( cChar $ ".+-" ) cChar := "" endif case cPic == "Y" if !( Upper( cChar ) $ "YN" ) cChar := "" endif case ( cPic == "$" .or. cPic == "*" ) .and. ::cType == "N" if ! IsDigit( cChar ) .and. !( cChar == "-" ) cChar := "" endif otherwise cChar := Transform( cChar, cPic ) endcase endif return cChar METHOD PutMask( xValue, lEdit ) CLASS Get local cChar local cBuffer local cPicFunc := ::cPicFunc local cPicMask := ::cPicMask local nFor local nNoEditable := 0 DEFAULT xValue TO ::VarGet() DEFAULT lEdit TO ::hasFocus if !( ValType( xValue ) $ "CNDL" ) xValue := "" endif if ::hasFocus cPicFunc := StrTran( cPicfunc, "B", "" ) if cPicFunc == "@" cPicFunc := "" endif endif if lEdit .and. ::lEdit if ( "*" $ cPicMask ) .or. ( "$" $ cPicMask ) cPicMask := StrTran( StrTran( cPicMask, "*", "9" ), "$", "9" ) endif endif cBuffer := Transform( xValue, ; iif( Empty( cPicFunc ), ; iif( ::lCleanZero .and. !::hasFocus, "@Z ", "" ), ; cPicFunc + iif( ::lCleanZero .and. !::hasFocus, "Z", "" ) + " " ) ; + cPicMask ) if ::cType == "N" if ( "(" $ cPicFunc .or. ")" $ cPicFunc ) .and. xValue >= 0 cBuffer += " " endif if ( ( "C" $ cPicFunc .and. xValue < 0 ) .or.; ( "X" $ cPicFunc .and. xValue >= 0 ) ) .and.; !( "X" $ cPicFunc .and. "C" $ cPicFunc ) cBuffer += " " endif if xValue < 0 ::lMinusPrinted := .T. else ::lMinusPrinted := .F. endif endif ::nMaxLen := Len( cBuffer ) ::nMaxEdit := ::nMaxLen if ::nDispLen == NIL ::nDispLen := ::nMaxLen endif if lEdit .and. ::cType == "N" .and. ! Empty( cPicMask ) if "E" $ cPicFunc cPicMask := Left( cPicMask, ::FirstEditable() - 1 ) + StrTran( SubStr( cPicMask, ::FirstEditable(), ::LastEditable() - ::FirstEditable( ) + 1 ), ",", Chr( 1 ) ) + SubStr( cPicMask, ::LastEditable() + 1 ) cPicMask := Left( cPicMask, ::FirstEditable() - 1 ) + StrTran( SubStr( cPicMask, ::FirstEditable(), ::LastEditable() - ::FirstEditable( ) + 1 ), ".", "," ) + SubStr( cPicMask, ::LastEditable() + 1 ) cPicMask := Left( cPicMask, ::FirstEditable() - 1 ) + StrTran( SubStr( cPicMask, ::FirstEditable(), ::LastEditable() - ::FirstEditable( ) + 1 ), Chr( 1 ), "." ) + SubStr( cPicMask, ::LastEditable() + 1 ) endif for nFor := 1 to ::nMaxLen cChar := SubStr( cPicMask, nFor, 1 ) if cChar $ ",." .and. SubStr( cBuffer, nFor, 1 ) $ ",." cBuffer := SubStr( cBuffer, 1, nFor - 1 ) + cChar + SubStr( cBuffer, nFor + 1 ) endif next if ::lEdit .and. Empty( xValue ) cBuffer := StrTran( cBuffer, "0", " " ) endif if ::lDecRev cBuffer := Left( cBuffer, ::FirstEditable() - 1 ) + StrTran( SubStr( cBuffer, ::FirstEditable(), ::LastEditable() - ::FirstEditable() + 1 ), ",", Chr( 1 ) ) + SubStr( cBuffer, ::LastEditable() + 1 ) cBuffer := Left( cBuffer, ::FirstEditable() - 1 ) + StrTran( SubStr( cBuffer, ::FirstEditable(), ::LastEditable() - ::FirstEditable() + 1 ), ".", "," ) + SubStr( cBuffer, ::LastEditable() + 1 ) cBuffer := Left( cBuffer, ::FirstEditable() - 1 ) + StrTran( SubStr( cBuffer, ::FirstEditable(), ::LastEditable() - ::FirstEditable() + 1 ), Chr( 1 ), "." ) + SubStr( cBuffer, ::LastEditable() + 1 ) endif endif if ::cType == "N" if "(" $ ::cPicFunc .or. ")" $ ::cPicFunc ::nMaxEdit-- endif if "C" $ ::cPicFunc .or. "X" $ ::cPicFunc ::nMaxEdit -= 3 endif endif if ::cType == "D" .and. ::BadDate cBuffer := ::cBuffer endif return cBuffer /* ------------------------------------------------------------------------- */ METHOD buffer( cBuffer ) CLASS Get if PCount() == 0 return ::cBuffer endif return iif( ::hasFocus, ::cBuffer := cBuffer, cBuffer ) /* NOTE: In contrary to CA-Cl*pper docs, this var is assignable. [vszakats] */ METHOD changed( lChanged ) CLASS Get if PCount() == 0 return ::lChanged endif if ISLOGICAL( lChanged ) return iif( ::hasFocus, ::lChanged := lChanged, lChanged ) endif return .F. METHOD clear( lClear ) CLASS Get if PCount() == 0 return ::lClear endif if ISLOGICAL( lClear ) return iif( ::hasFocus, ::lClear := lClear, lClear ) endif return .F. METHOD minus( lMinus ) CLASS Get if PCount() == 0 return ::lMinus endif if ISLOGICAL( lMinus ) return iif( ::hasFocus, ::lMinus := lMinus, lMinus ) endif return .F. /* NOTE: CA-Cl*pper has a bug where negative nRow value will be translated to 16bit unsigned int, so the behaviour will be different in this case. [vszakats] */ METHOD row( nRow ) CLASS Get if PCount() > 0 ::nRow := iif( ISNUMBER( nRow ), nRow, 0 ) endif return ::nRow /* NOTE: CA-Cl*pper has a bug where negative nCol value will be translated to 16bit unsigned int, so the behaviour will be different in this case. [vszakats] */ METHOD col( nCol ) CLASS Get if PCount() > 0 ::nCol := iif( ISNUMBER( nCol ), nCol, 0 ) endif return ::nCol METHOD name( cName ) CLASS Get if PCount() > 0 .and. cName != NIL ::cName := cName endif return ::cName #ifdef HB_EXTENSION METHOD hideInput( lHideInput ) CLASS Get if lHideInput != NIL ::lHideInput := _eInstVar( Self, "HIDEINPUT", lHideInput, "L", 1001 ) endif return ::lHideInput METHOD style( cStyle ) CLASS Get if cStyle != NIL ::cStyle := _eInstVar( Self, "STYLE", cStyle, "C", 1001, {|| Len( cStyle ) == 1 } ) endif return ::cStyle #endif /* ------------------------------------------------------------------------- */ METHOD New( nRow, nCol, bVarBlock, cVarName, cPicture, cColorSpec ) CLASS Get DEFAULT nRow TO Row() DEFAULT nCol TO Col() + iif( Set( _SET_DELIMITERS ), 1, 0 ) DEFAULT cVarName TO "" DEFAULT bVarBlock TO iif( ISCHARACTER( cVarName ), MemvarBlock( cVarName ), NIL ) #ifdef HB_COMPAT_C53 DEFAULT cColorSpec TO hb_ColorIndex( SetColor(), CLR_UNSELECTED ) + "," +; hb_ColorIndex( SetColor(), CLR_ENHANCED ) + "," +; hb_ColorIndex( SetColor(), CLR_STANDARD ) + "," +; iif( IsDefColor(), iif( Set( _SET_INTENSITY ), "W+/N", "W/N" ), hb_ColorIndex( SetColor(), CLR_BACKGROUND ) ) #else DEFAULT cColorSpec TO hb_ColorIndex( SetColor(), CLR_UNSELECTED ) + "," +; hb_ColorIndex( SetColor(), CLR_ENHANCED ) #endif ::nRow := nRow ::nCol := nCol ::bBlock := bVarBlock ::cName := cVarName ::Picture := cPicture ::ColorSpec := cColorSpec return Self