EditField.st
changeset 125 3ffa271732f7
parent 122 04ec3fda7c11
child 127 462396b08e30
equal deleted inserted replaced
124:7abd3a234296 125:3ffa271732f7
     8  be provided or otherwise made available to, or used by, any
     8  be provided or otherwise made available to, or used by, any
     9  other person.  No title to or ownership of the software is
     9  other person.  No title to or ownership of the software is
    10  hereby transferred.
    10  hereby transferred.
    11 "
    11 "
    12 
    12 
    13 'From Smalltalk/X, Version:2.10.5 on 4-may-1995 at 8:46:55 am'!
    13 'From Smalltalk/X, Version:2.10.5 on 9-may-1995 at 12:09:38 pm'!
    14 
    14 
    15 EditTextView subclass:#EditField
    15 EditTextView subclass:#EditField
    16 	 instanceVariableNames:'leaveAction enabled enableAction crAction tabAction
    16 	 instanceVariableNames:'leaveAction enabled enableAction crAction tabAction converter
    17 		converter acceptAction leaveKeys alwaysAccept acceptOnLeave acceptOnReturn'
    17                 leaveKeys immediateAccept acceptOnLeave acceptOnReturn
       
    18                 lengthLimit'
    18 	 classVariableNames:'DefaultForegroundColor DefaultBackgroundColor
    19 	 classVariableNames:'DefaultForegroundColor DefaultBackgroundColor
    19 		DefaultSelectionForegroundColor DefaultSelectionBackgroundColor
    20                 DefaultSelectionForegroundColor DefaultSelectionBackgroundColor
    20 		DefaultFont'
    21                 DefaultFont'
    21 	 poolDictionaries:''
    22 	 poolDictionaries:''
    22 	 category:'Views-Text'
    23 	 category:'Views-Text'
    23 !
    24 !
    24 
    25 
    25 EditField comment:'
    26 EditField comment:'
    26 COPYRIGHT (c) 1990 by Claus Gittinger
    27 COPYRIGHT (c) 1990 by Claus Gittinger
    27 	      All Rights Reserved
    28 	      All Rights Reserved
    28 
    29 
    29 $Header: /cvs/stx/stx/libwidg/EditField.st,v 1.20 1995-05-07 00:15:56 claus Exp $
    30 $Header: /cvs/stx/stx/libwidg/EditField.st,v 1.21 1995-05-09 01:55:33 claus Exp $
    30 '!
    31 '!
    31 
    32 
    32 !EditField class methodsFor:'documentation'!
    33 !EditField class methodsFor:'documentation'!
    33 
    34 
    34 copyright
    35 copyright
    45 "
    46 "
    46 !
    47 !
    47 
    48 
    48 version
    49 version
    49 "
    50 "
    50 $Header: /cvs/stx/stx/libwidg/EditField.st,v 1.20 1995-05-07 00:15:56 claus Exp $
    51 $Header: /cvs/stx/stx/libwidg/EditField.st,v 1.21 1995-05-09 01:55:33 claus Exp $
    51 "
    52 "
    52 !
    53 !
    53 
    54 
    54 documentation
    55 documentation
    55 "
    56 "
    56     an editable text-field. Realized by using an EditTextView,
    57     an editable text-field. Realized by using an EditTextView,
    57     and forcing its size to 1 line - disabling cursor movement
    58     and forcing its size to 1 line - disabling cursor movement
    58     in the vertical direction.
    59     in the vertical direction.
    59     An action (leaveAction) is performed when the field is left
       
    60     by either Return or a cursor movement, or if 'accept' is
       
    61     performed from the menu.
       
    62 
    60 
    63     Instance variables:
    61     Instance variables:
    64 
    62 
    65       leaveAction    <Block | nil>              if non-nil, this is evaluated with
    63       leaveAction    <Block | nil>              if non-nil, this is evaluated with
    66 						the key (#Return, #CursorUp etc.) when
    64 						the key (#Return, #CursorUp etc.) when
    68 						(fieldGroups use this to decide which
    66 						(fieldGroups use this to decide which
    69 						 field has to be enabled next)
    67 						 field has to be enabled next)
    70 
    68 
    71       enabled        <Boolean>                  if false, input is ignored.
    69       enabled        <Boolean>                  if false, input is ignored.
    72 
    70 
    73       enableAction   <Block | nil>
    71       enableAction   <Block | nil>              action performed if the field is
       
    72 						enabled via an explicit click.
       
    73 						(this is used by the group to
       
    74 						 set the active field to the clicked upon field)
    74 
    75 
    75       crAction       <Block | nil>              if non-nil, keyboard input of a cr are not
    76       crAction       <Block | nil>              if non-nil, keyboard input of a cr are not
    76 						handled specially, instead this block is evaluated
    77 						handled specially, instead this block is evaluated
    77 						(however, this block can perform additional checks and send
    78 						(however, this block can perform additional checks and send
    78 						 a #accept then)
    79 						 a #accept then)
    83 
    84 
    84       converter      <PrintConverter | nil>     if non-nil, this is supposed to convert between
    85       converter      <PrintConverter | nil>     if non-nil, this is supposed to convert between
    85 						the object and its printed representation.
    86 						the object and its printed representation.
    86 						Defaults to nil i.e. assume that strings are edited.
    87 						Defaults to nil i.e. assume that strings are edited.
    87 
    88 
    88       acceptAction   <Block | nil>              if non-nil, this is performed in addition to
       
    89 						the leaveAction.
       
    90 
       
    91       leaveKeys      <Collection>               keys which are interpreted as 'leving the field'
    89       leaveKeys      <Collection>               keys which are interpreted as 'leving the field'
    92 
    90 
    93       alwaysAccept   <Boolean>                  if true, every change of the text is immediately
    91       immediateAccept   <Boolean>               if true, every change of the text is immediately
    94 						forwardd to the model/acceptBlock.
    92 						forwarded to the model/acceptBlock. If false,
    95 						Default is false i.e. only forward changes
    93 						the changed value is only stored in the model
    96 						on accept.
    94 						if the field is left or accepted.
       
    95 						Default is false.
    97 
    96 
    98       acceptOnLeave  <Boolean>                  if true, leaving the field (via cursor keys)
    97       acceptOnLeave  <Boolean>                  if true, leaving the field (via cursor keys)
    99 						automatically accepts the value into the model.
    98 						automatically accepts the value into the model.
   100 						Default is false.
    99 						Default is false.
   101 
   100 
   121 	field width:1.0.        'let its height as-is'.
   120 	field width:1.0.        'let its height as-is'.
   122 
   121 
   123 	top open
   122 	top open
   124 
   123 
   125 
   124 
   126     forward input in topView to field:
   125     forward input in topView to the field:
       
   126     (currently, the field does not know this - therefore,
       
   127      its been told here ... this may change)
   127 
   128 
   128 	|top field|
   129 	|top field|
   129 
   130 
   130 	top := StandardSystemView new.
   131 	top := StandardSystemView new.
   131 	top extent:200@100.
   132 	top extent:200@100.
   132 
   133 
   133 	field := EditField origin:0.0@0.0 in:top.
   134 	field := EditField origin:0.0@0.0 in:top.
   134 	field width:1.0.        'let its height as-is'.
   135 	field width:1.0.        'let its height as-is'.
   135 
   136 
   136 	top delegate:(KeyboardForwarder toView:field).
   137 	top delegate:(KeyboardForwarder toView:field).
       
   138 	field hasKeyboardFocus:true.
   137 	top open
   139 	top open
   138 
   140 
   139 
   141 
   140     just to make it look better: set some inset:
   142     to make it look better: set some inset:
   141 
   143 
   142 	|top field|
   144 	|top field|
   143 
   145 
   144 	top := StandardSystemView new.
   146 	top := StandardSystemView new.
   145 	top extent:200@100.
   147 	top extent:200@100.
   166 	field editValue:'hello world'.
   168 	field editValue:'hello world'.
   167 
   169 
   168 	top open
   170 	top open
   169 
   171 
   170 
   172 
   171     and have it preselected:
   173     have it preselected:
   172 
   174 
   173 	|top field|
   175 	|top field|
   174 
   176 
   175 	top := StandardSystemView new.
   177 	top := StandardSystemView new.
   176 	top extent:200@100.
   178 	top extent:200@100.
   199 	      selectFromCharacterPosition:1 to:5.
   201 	      selectFromCharacterPosition:1 to:5.
   200 
   202 
   201 	top open
   203 	top open
   202 
   204 
   203 
   205 
       
   206     set a size limit:
       
   207 
       
   208 	|top field|
       
   209 
       
   210 	top := StandardSystemView new.
       
   211 	top extent:200@100.
       
   212 
       
   213 	field := EditField origin:0.0@ViewSpacing in:top.
       
   214 	field width:1.0.     
       
   215 	field leftInset:ViewSpacing;
       
   216 	      rightInset:ViewSpacing.
       
   217 	field editValue:'hello';
       
   218 	      maxChars:8.
       
   219 
       
   220 	top open
       
   221 
       
   222 
   204     use a converter:
   223     use a converter:
   205       - numbers:
   224       - numbers (default to 0):
   206 
   225 
   207 	|top field|
   226 	|top field|
   208 
   227 
   209 	top := StandardSystemView new.
   228 	top := StandardSystemView new.
   210 	top extent:200@100.
   229 	top extent:200@100.
   232 	field leftInset:ViewSpacing;
   251 	field leftInset:ViewSpacing;
   233 	      rightInset:ViewSpacing.
   252 	      rightInset:ViewSpacing.
   234 
   253 
   235 	field converter:(PrintConverter new initForDate).
   254 	field converter:(PrintConverter new initForDate).
   236 	field editValue:Date today.
   255 	field editValue:Date today.
   237 	field acceptAction:[:value | Transcript show:value class name; space; showCr:value].
   256 	field acceptAction:[:value | Transcript showCr:value class name , ' ' , value printString].
   238 	field crAction:[field accept. top destroy].
   257 	field crAction:[field accept. top destroy].
   239 	top open.
   258 	top open.
   240 
   259 
   241 
   260 
   242     setting alwaysAccept, makes the field update with every key:
   261     setting immediateAccept, makes the field update with every key:
   243       - numbers:
   262 
       
   263       - immediate accept numbers, defaulting to nil:
   244 
   264 
   245 	|top field|
   265 	|top field|
   246 
   266 
   247 	top := StandardSystemView new.
   267 	top := StandardSystemView new.
   248 	top extent:200@100.
   268 	top extent:200@100.
   250 	field := EditField origin:0.0@ViewSpacing in:top.
   270 	field := EditField origin:0.0@ViewSpacing in:top.
   251 	field width:1.0.
   271 	field width:1.0.
   252 	field leftInset:ViewSpacing;
   272 	field leftInset:ViewSpacing;
   253 	      rightInset:ViewSpacing.
   273 	      rightInset:ViewSpacing.
   254 
   274 
   255 	field converter:(PrintConverter new initForNumber).
   275 	field converter:(PrintConverter new initForNumberOrNil).
   256 	field alwaysAccept:true.
   276 	field immediateAccept:true.
   257 	field editValue:1234.
   277 	field editValue:1234.
   258 	field acceptAction:[:value | Transcript showCr:value].
   278 	field acceptAction:[:value | Transcript showCr:value].
   259 	field crAction:[field accept. top destroy].
   279 	field crAction:[field accept. top destroy].
   260 	top open.
   280 	top open.
   261 
   281 
   302 	field2 leftInset:ViewSpacing;
   322 	field2 leftInset:ViewSpacing;
   303 	      rightInset:ViewSpacing.
   323 	      rightInset:ViewSpacing.
   304 	field2 model:model.
   324 	field2 model:model.
   305 	top2 open.
   325 	top2 open.
   306 
   326 
       
   327     with immediate accept:
       
   328 
       
   329 	|top1 top2 field1 field2 model|
       
   330 
       
   331 	model := 'hello world' asValue.
       
   332 
       
   333 	top1 := StandardSystemView new.
       
   334 	top1 extent:200@100.
       
   335 	field1 := EditField origin:0.0@ViewSpacing in:top1.
       
   336 	field1 width:1.0.
       
   337 	field1 leftInset:ViewSpacing; rightInset:ViewSpacing.
       
   338 	field1 model:model; immediateAccept:true.
       
   339 	top1 open.
       
   340 
       
   341 	top2 := StandardSystemView new.
       
   342 	top2 extent:200@100.
       
   343 	field2 := EditField origin:0.0@ViewSpacing in:top2.
       
   344 	field2 width:1.0.
       
   345 	field2 leftInset:ViewSpacing; rightInset:ViewSpacing.
       
   346 	field2 model:model; immediateAccept:true.
       
   347 	top2 open.
   307 
   348 
   308     just an example; a checkBox and an editField on the same model:
   349     just an example; a checkBox and an editField on the same model:
   309 
   350 
   310 	|top1 top2 field1 box model|
   351 	|top1 top2 field1 box model|
   311 
   352 
   327 	box label:'on/off'.
   368 	box label:'on/off'.
   328 	top2 add:box.
   369 	top2 add:box.
   329 	top2 open.
   370 	top2 open.
   330 
   371 
   331 	model inspect.
   372 	model inspect.
       
   373 
       
   374 
       
   375     connecting fields:
       
   376     update field2 wehenever field1 is changed.
       
   377     (normally, the processing below (xChanged) is done in your application
       
   378      class, or in a complex model. For the demonstration below, we use
       
   379      a Plug to simulate the protocol.)
       
   380 
       
   381 	|application top field1 field2 value1 value2|
       
   382 
       
   383 	application := Plug new.
       
   384 	application respondTo:#value1Changed
       
   385 			 with:[value2 value:(value1 value isNil ifTrue:[nil]
       
   386 								ifFalse:[value1 value squared])].
       
   387 
       
   388 	value1 := 1 asValue.
       
   389 	value2 := 1 asValue.
       
   390 
       
   391 	top := Dialog new.
       
   392 	top extent:200@200.
       
   393 
       
   394 	(top addTextLabel:'some number:') layout:#left.
       
   395 	top addVerticalSpace.
       
   396 
       
   397 	(top addInputFieldOn:value1 tabable:false) 
       
   398 	    converter:(PrintConverter new initForNumberOrNil);
       
   399 	    immediateAccept:true.
       
   400 	top addVerticalSpace.
       
   401 
       
   402 	(top addTextLabel:'squared:') layout:#left.
       
   403 	top addVerticalSpace.
       
   404 	(top addInputFieldOn:value2 tabable:false) 
       
   405 	    converter:(PrintConverter new initForNumberOrNil).
       
   406 
       
   407 	value1 onChangeSend:#value1Changed to:application.
       
   408 
       
   409 	top openModeless.
       
   410 
       
   411 
       
   412     two-way connect:
       
   413     each field updates the other (notice, that we have to turn off
       
   414     onChange: notification, to avoid an endless notification cycle)
       
   415 
       
   416 	|application top field1 field2 value1 value2|
       
   417 
       
   418 	application := Plug new.
       
   419 	application respondTo:#value1Changed
       
   420 			 with:[value2 retractInterrestFor:application.
       
   421 			       value2 value:(value1 value isNil ifTrue:[nil]
       
   422 								ifFalse:[value1 value squared]).
       
   423 			       value2 onChangeSend:#value2Changed to:application.
       
   424 			      ].
       
   425 	application respondTo:#value2Changed
       
   426 			 with:[value1 retractInterrestFor:application.
       
   427 			       value1 value:(value2 value isNil ifTrue:[nil]
       
   428 								ifFalse:[value2 value sqrt]).
       
   429 			       value1 onChangeSend:#value1Changed to:application.
       
   430 			      ].
       
   431 
       
   432 	value1 := 1 asValue.
       
   433 	value2 := 1 asValue.
       
   434 
       
   435 	top := Dialog new.
       
   436 	top extent:200@200.
       
   437 
       
   438 	(top addTextLabel:'some number:') layout:#left.
       
   439 	top addVerticalSpace.
       
   440 
       
   441 	(top addInputFieldOn:value1 tabable:false) 
       
   442 	    converter:(PrintConverter new initForNumberOrNil);
       
   443 	    immediateAccept:true.
       
   444 	top addVerticalSpace.
       
   445 
       
   446 	(top addTextLabel:'squared:') layout:#left.
       
   447 	top addVerticalSpace.
       
   448 	(top addInputFieldOn:value2 tabable:false) 
       
   449 	    converter:(PrintConverter new initForNumberOrNil).
       
   450 
       
   451 	value1 onChangeSend:#value1Changed to:application.
       
   452 	value2 onChangeSend:#value2Changed to:application.
       
   453 
       
   454 	top openModeless.
   332 "
   455 "
   333 ! !
   456 ! !
   334 
   457 
   335 !EditField class methodsFor:'defaults'!
   458 !EditField class methodsFor:'defaults'!
       
   459 
       
   460 defaultLeaveKeys
       
   461     ^ #(Return CursorUp CursorDown Next Previous Accept)
       
   462 !
   336 
   463 
   337 updateStyleCache
   464 updateStyleCache
   338     DefaultForegroundColor := StyleSheet colorAt:'editFieldForegroundColor' default:Black.
   465     DefaultForegroundColor := StyleSheet colorAt:'editFieldForegroundColor' default:Black.
   339     DefaultBackgroundColor := StyleSheet colorAt:'editFieldBackgroundColor' default:White.
   466     DefaultBackgroundColor := StyleSheet colorAt:'editFieldBackgroundColor' default:White.
   340     DefaultSelectionForegroundColor := StyleSheet colorAt:'editFieldSelectionForegroundColor' default:DefaultBackgroundColor.
   467     DefaultSelectionForegroundColor := StyleSheet colorAt:'editFieldSelectionForegroundColor' default:DefaultBackgroundColor.
   344     "
   471     "
   345      self updateStyleCache
   472      self updateStyleCache
   346     "
   473     "
   347 !
   474 !
   348 
   475 
   349 defaultLeaveKeys
       
   350     ^ #(Return CursorUp CursorDown Next Previous Accept)
       
   351 !
       
   352 
       
   353 defaultNumberOfLines
   476 defaultNumberOfLines
   354     "the number of lines in the field"
   477     "the number of lines in the field"
   355 
   478 
   356     ^ 1
   479     ^ 1
   357 ! !
   480 ! !
   358 
   481 
       
   482 !EditField methodsFor:'private'!
       
   483 
       
   484 textChanged
       
   485     "this is sent by mySelf (somewhere in a superclass) whenever
       
   486      my contents has changed. 
       
   487      A good place to add immediateAccept functionality and check for the
       
   488      lengthLimit."
       
   489 
       
   490     |string|
       
   491 
       
   492     super textChanged.
       
   493     string := self contents.
       
   494     lengthLimit notNil ifTrue:[
       
   495 	string size > lengthLimit ifTrue:[
       
   496 	    self contents:(string := string copyTo:lengthLimit).
       
   497 	    self flash.
       
   498 	]
       
   499     ].
       
   500     immediateAccept ifTrue:[
       
   501 	self accept
       
   502     ]
       
   503 !
       
   504 
       
   505 getListFromModel
       
   506     "redefined to aquire the text via the aspectMsg - not the listMsg,
       
   507      and to ignore updates resulting from my own change."
       
   508 
       
   509     "
       
   510      ignore updates from my own change
       
   511     "
       
   512     lockUpdates ifTrue:[
       
   513 	lockUpdates := false.
       
   514 	^ self
       
   515     ].
       
   516 
       
   517     (model notNil and:[aspectMsg notNil]) ifTrue:[
       
   518 	self editValue:(model perform:aspectMsg).
       
   519     ]
       
   520 !
       
   521 
       
   522 startAutoScrollUp:y
       
   523     "no vertical scrolling in editfields"
       
   524 
       
   525     ^ self
       
   526 !
       
   527 
       
   528 startAutoScrollDown:y
       
   529     "no vertical scrolling in editfields"
       
   530 
       
   531     ^ self
       
   532 ! !
       
   533 
       
   534 !EditField methodsFor:'accessing'!
       
   535 
       
   536 contents
       
   537     "return contents as a string
       
   538      - redefined since EditFields hold only one line of text.
       
   539     In your application, please use #editValue; 
       
   540     it uses a converter (if any) and is compatible to ST-80."
       
   541 
       
   542     list isNil ifTrue:[^ ''].
       
   543     (list size == 0) ifTrue:[^ ''].
       
   544     ^ list at:1
       
   545 !
       
   546 
       
   547 leaveAction:aBlock
       
   548     "define an action to be evaluated when field is left by return key"
       
   549 
       
   550     leaveAction := aBlock
       
   551 !
       
   552 
       
   553 list:someText
       
   554     "redefined to force text to 1 line, and notify dependents
       
   555      of any changed extent-wishes."
       
   556 
       
   557     |l oldWidth|
       
   558 
       
   559     l := someText.
       
   560     l size > 1 ifTrue:[
       
   561 	l := OrderedCollection with:(l at:1)
       
   562     ].
       
   563     oldWidth := self widthOfContents.
       
   564     super list:l.
       
   565     self widthOfContents ~~ oldWidth ifTrue:[
       
   566 	self changed:#preferedExtent
       
   567     ]
       
   568 !
       
   569 
       
   570 contents:someText
       
   571     "set the contents from a string
       
   572      - redefined to place the cursor to the end.
       
   573     In your application, please use #editValue:; 
       
   574     it uses a converter (if any) and is compatible to ST-80."
       
   575 
       
   576     super contents:someText.
       
   577     self cursorCol:(someText size + 1).
       
   578 !
       
   579 
       
   580 enable
       
   581     "enable the field; show cursor and allow input"
       
   582 
       
   583     enabled ifFalse:[
       
   584 "/        enableAction notNil ifTrue:[
       
   585 "/            enableAction value
       
   586 "/        ].
       
   587 	enabled := true.
       
   588 	super showCursor
       
   589     ]
       
   590 !
       
   591 
       
   592 immediateAccept:aBoolean
       
   593     "set/clear the immediateAccept flag. The default is false."
       
   594 
       
   595      immediateAccept := aBoolean
       
   596 !
       
   597 
       
   598 editValue
       
   599     "if the field edits a string, this is a name alias for #contents.
       
   600      Otherwise, if there is a converter, return the edited string
       
   601      converted to an appropriate object."
       
   602 
       
   603     |string|
       
   604 
       
   605     string := self contents.
       
   606     converter isNil ifTrue:[^ string].
       
   607     string isNil ifTrue:[string := ''].
       
   608     ^ converter readValueFrom:string 
       
   609 !
       
   610 
       
   611 leaveKeys:aCollectionOfKeySymbols 
       
   612     "define the set of keys which are interpreted as leaveKeys.
       
   613      I.e. those that make the field inactive and accept (if acceptOnLeave is true).
       
   614      The default is a set of #CursorUp, #CursorDown, #Next, #Prior and #Return."
       
   615 
       
   616     leaveKeys := aCollectionOfKeySymbols
       
   617 !
       
   618 
       
   619 initialText:aString selected:aBoolean
       
   620     "set the initialText and select it if aBoolean is true"
       
   621 
       
   622     |len s|
       
   623 
       
   624     leftOffset := 0.
       
   625     aString isNil ifTrue:[
       
   626 	s := nil
       
   627     ] ifFalse:[
       
   628 	s := aString asString
       
   629     ].
       
   630     self contents:s.
       
   631     aBoolean ifTrue:[
       
   632 	(len := s size) ~~ 0 ifTrue:[
       
   633 	    self selectFromLine:1 col:1 toLine:1 col:len
       
   634 	]
       
   635     ]
       
   636 !
       
   637 
       
   638 crAction:aBlock
       
   639     "define an action to be evaluated when the return key is pressed."
       
   640 
       
   641     crAction := aBlock
       
   642 !
       
   643 
       
   644 tabAction:aBlock
       
   645     "define an action to be evaluated when the tabulator key is pressed."
       
   646 
       
   647     tabAction := aBlock
       
   648 !
       
   649 
       
   650 acceptOnReturn:aBoolean
       
   651     "set/clear the acceptOnReturn flag. The default is true."
       
   652 
       
   653      acceptOnReturn := aBoolean
       
   654 !
       
   655 
       
   656 initialText:aString
       
   657     "set the initialText and select it"
       
   658 
       
   659     self initialText:aString selected:true
       
   660 !
       
   661 
       
   662 editValue:aStringOrObject
       
   663     "set the contents. If there is a converter, use it to convert
       
   664      the object into a printed representation.
       
   665      Otherwise, the argument is supposed to be a string like object,
       
   666      and used directly (i.e. this is equivalent to sending #contents:)."
       
   667 
       
   668     self editValue:aStringOrObject selected:false
       
   669 !
       
   670 
       
   671 disable
       
   672     "disable the field; hide cursor and ignore input"
       
   673 
       
   674     enabled ifTrue:[
       
   675 	enabled := false.
       
   676 	self hideCursor
       
   677     ]
       
   678 !
       
   679 
       
   680 editValue:aStringOrObject selected:aBoolean
       
   681     "set the contents. If there is a converter, use it to convert
       
   682      the object into a printed representation.
       
   683      Otherwise, the argument is supposed to be a string like object,
       
   684      and used directly (i.e. this is equivalent to sending #contents:)."
       
   685 
       
   686     |string|
       
   687 
       
   688     converter notNil ifTrue:[
       
   689 	string := converter printStringFor:aStringOrObject
       
   690     ] ifFalse:[
       
   691 	string :=  aStringOrObject.
       
   692     ].
       
   693     self contents:string.
       
   694     aBoolean ifTrue:[
       
   695 	self selectFromLine:1 col:1 toLine:1 col:string size
       
   696     ]
       
   697 !
       
   698 
       
   699 acceptOnLeave:aBoolean
       
   700     "set/clear the acceptOnLeave flag. The default is false."
       
   701 
       
   702      acceptOnLeave := aBoolean
       
   703 !
       
   704 
       
   705 converter:aConverter
       
   706     "set the converter. If non-nil,
       
   707      the converter is applied to the text to convert from the string
       
   708      representation to the actual object value and vice versa.
       
   709      The default converter is nil, meaning no-conversion
       
   710      (i.e. the edited object is the string itself."
       
   711 
       
   712     converter := aConverter
       
   713 !
       
   714 
       
   715 enableAction:aBlock
       
   716     "define an action to be evaluated when enabled by clicking upon"
       
   717 
       
   718     enableAction := aBlock
       
   719 !
       
   720 
       
   721 converter
       
   722     "return the converter (if any)."
       
   723 
       
   724     ^ converter
       
   725 !
       
   726 
       
   727 maxChars:aNumberOrNil
       
   728     "set the maximum number of characters that are allowed in
       
   729      the field. Additional input will be ignored by the field.
       
   730      A limit of nil means: unlimited. This is the default.
       
   731      This method has been renamed from #lengthLimit: for ST-80
       
   732      compatibility."
       
   733 
       
   734     lengthLimit := aNumberOrNil
       
   735 !
       
   736 
       
   737 stringValue
       
   738     "alias for #contents - for ST-80 compatibility"
       
   739 
       
   740     ^ self contents
       
   741 ! !
       
   742 
   359 !EditField methodsFor:'initialization'!
   743 !EditField methodsFor:'initialization'!
       
   744 
       
   745 initStyle
       
   746     super initStyle.
       
   747 
       
   748     DefaultBackgroundColor notNil ifTrue:[
       
   749 	bgColor := DefaultBackgroundColor on:device.
       
   750 	self viewBackground:bgColor.
       
   751     ].
       
   752     fgColor := DefaultForegroundColor.
       
   753     selectionFgColor := DefaultSelectionForegroundColor.
       
   754     selectionBgColor := DefaultSelectionBackgroundColor.
       
   755 
       
   756     DefaultFont notNil ifTrue:[
       
   757 	font := DefaultFont on:device
       
   758     ]
       
   759 !
   360 
   760 
   361 initialize
   761 initialize
   362     super initialize.
   762     super initialize.
   363     self height:(font height + font descent + (topMargin * 2)).
   763     self height:(font height + font descent + (topMargin * 2)).
   364     enabled := true.
   764     enabled := true.
   365     fixedSize := true.
   765     fixedSize := true.
   366     nFullLinesShown := 1.
   766     nFullLinesShown := 1.
   367     nLinesShown := 1.
   767     nLinesShown := 1.
   368     alwaysAccept := false.
   768     immediateAccept := acceptOnLeave := false.
   369     acceptOnLeave := false.
       
   370     acceptOnReturn := true.
   769     acceptOnReturn := true.
       
   770     cursorShown := true.
   371     leaveKeys := self class defaultLeaveKeys.
   771     leaveKeys := self class defaultLeaveKeys.
   372     cursorShown := true
       
   373 !
       
   374 
       
   375 initStyle
       
   376     super initStyle.
       
   377 
       
   378     DefaultBackgroundColor notNil ifTrue:[
       
   379 	bgColor := DefaultBackgroundColor on:device.
       
   380 	self viewBackground:bgColor.
       
   381     ].
       
   382     fgColor := DefaultForegroundColor.
       
   383     selectionFgColor := DefaultSelectionForegroundColor.
       
   384     selectionBgColor := DefaultSelectionBackgroundColor.
       
   385 
       
   386     DefaultFont notNil ifTrue:[
       
   387 	font := DefaultFont on:device
       
   388     ]
       
   389 !
   772 !
   390 
   773 
   391 editMenu
   774 editMenu
   392     |labels selectors m|
   775     |labels selectors m|
   393 
   776 
   431     "scroll back to beginning when realized"
   814     "scroll back to beginning when realized"
   432     leftOffset := 0.
   815     leftOffset := 0.
   433     super realize
   816     super realize
   434 ! !
   817 ! !
   435 
   818 
   436 !EditField methodsFor:'private'!
       
   437 
       
   438 getListFromModel
       
   439     "redefined to aquire the text via the aspectMsg - not the listMsg"
       
   440 
       
   441     |savedCursorCol|
       
   442 
       
   443     (model notNil and:[aspectMsg notNil]) ifTrue:[
       
   444 	"
       
   445 	 kludge: editValue positions cursor to beginning
       
   446 	"
       
   447 	savedCursorCol := cursorCol.
       
   448 	self editValue:(model perform:aspectMsg).
       
   449 	savedCursorCol ~~ 1 ifTrue:[self cursorLine:1 col:savedCursorCol].
       
   450 	cursorVisibleLine := 1.
       
   451     ]
       
   452 !
       
   453 
       
   454 textChanged
       
   455     super textChanged.
       
   456     alwaysAccept ifTrue:[
       
   457 	self accept
       
   458     ]
       
   459 !
       
   460 
       
   461 startAutoScrollUp:y
       
   462     "no vertical scrolling in editfields"
       
   463 
       
   464     ^ self
       
   465 !
       
   466 
       
   467 startAutoScrollDown:y
       
   468     "no vertical scrolling in editfields"
       
   469 
       
   470     ^ self
       
   471 ! !
       
   472 
       
   473 !EditField methodsFor:'queries'!
   819 !EditField methodsFor:'queries'!
   474 
   820 
   475 preferedExtent
   821 preferedExtent
   476     "return the prefered extent of this view.
   822     "return the prefered extent of this view.
   477      That is the width of the string plus some extra, 
   823      That is the width of the string plus some extra, 
   486     w := (((font on:device) widthOf:string) * 1.5) rounded.
   832     w := (((font on:device) widthOf:string) * 1.5) rounded.
   487     w := w min:(device width // 2).
   833     w := w min:(device width // 2).
   488     ^ w @ self height
   834     ^ w @ self height
   489 ! !
   835 ! !
   490 
   836 
   491 !EditField methodsFor:'accessing'!
       
   492 
       
   493 list:someText
       
   494     "redefined to force text to 1 line, and notify dependents
       
   495      of any changed extent-wishes."
       
   496 
       
   497     |l oldWidth|
       
   498 
       
   499     l := someText.
       
   500     l size > 1 ifTrue:[
       
   501 	l := OrderedCollection with:(l at:1)
       
   502     ].
       
   503     oldWidth := self widthOfContents.
       
   504     super list:l.
       
   505     self widthOfContents ~~ oldWidth ifTrue:[
       
   506 	self changed:#preferedExtent
       
   507     ]
       
   508 !
       
   509 
       
   510 contents:someText
       
   511     "set the contents from a string
       
   512      - redefined to place the cursor to the end.
       
   513     In your application, please use #editValue:; 
       
   514     it uses a converter (if any) and is compatible to ST-80."
       
   515 
       
   516     super contents:someText.
       
   517     self cursorCol:(someText size + 1).
       
   518 !
       
   519 
       
   520 contents
       
   521     "return contents as a string
       
   522      - redefined since EditFields hold only one line of text.
       
   523     In your application, please use #editValue; 
       
   524     it uses a converter (if any) and is compatible to ST-80."
       
   525 
       
   526     list isNil ifTrue:[^ ''].
       
   527     (list size == 0) ifTrue:[^ ''].
       
   528     ^ list at:1
       
   529 !
       
   530 
       
   531 enable
       
   532     "enable the field; show cursor and allow input"
       
   533 
       
   534     enabled ifFalse:[
       
   535 	enableAction notNil ifTrue:[
       
   536 	    enableAction value
       
   537 	].
       
   538 	enabled := true.
       
   539 	super showCursor
       
   540     ]
       
   541 !
       
   542 
       
   543 leaveAction:aBlock
       
   544     "define an action to be evaluated when field is left by return key"
       
   545 
       
   546     leaveAction := aBlock
       
   547 !
       
   548 
       
   549 leaveKeys:aCollectionOfKeySymbols 
       
   550     "define the set of keys which are interpreted as leaveKeys.
       
   551      I.e. those that make the field inactive and accept (if acceptOnLeave is true).
       
   552      The default is a set of #CursorUp, #CursorDown, #Next, #Prior and #Return."
       
   553 
       
   554     leaveKeys := aCollectionOfKeySymbols
       
   555 !
       
   556 
       
   557 crAction:aBlock
       
   558     "define an action to be evaluated when the return key is pressed."
       
   559 
       
   560     crAction := aBlock
       
   561 !
       
   562 
       
   563 acceptAction:aBlock
       
   564     "define an action to be evaluated when accepted."
       
   565 
       
   566     acceptAction := aBlock
       
   567 !
       
   568 
       
   569 tabAction:aBlock
       
   570     "define an action to be evaluated when the tabulator key is pressed."
       
   571 
       
   572     tabAction := aBlock
       
   573 !
       
   574 
       
   575 alwaysAccept:aBoolean
       
   576     "set/clear the alwaysAccept flag. The default is false."
       
   577 
       
   578      alwaysAccept := aBoolean
       
   579 !
       
   580 
       
   581 acceptOnReturn:aBoolean
       
   582     "set/clear the acceptOnReturn flag. The default is true."
       
   583 
       
   584      acceptOnReturn := aBoolean
       
   585 !
       
   586 
       
   587 acceptOnLeave:aBoolean
       
   588     "set/clear the acceptOnLeave flag. The default is false."
       
   589 
       
   590      acceptOnLeave := aBoolean
       
   591 !
       
   592 
       
   593 converter
       
   594     "return the converter (if any)."
       
   595 
       
   596     ^ converter
       
   597 !
       
   598 
       
   599 editValue
       
   600     "if the field edits a string, this is a name alias for #contents.
       
   601      Otherwise, if there is a converter, return the edited string
       
   602      converted to an appropriate object."
       
   603 
       
   604     |text|
       
   605 
       
   606     text := self contents.
       
   607     converter isNil ifTrue:[^ text].
       
   608     ^ converter readValueFrom:text withoutSpaces
       
   609 !
       
   610 
       
   611 editValue:aStringOrObject
       
   612     "set the contents. If there is a converter, use it to convert
       
   613      the object into a printed representation.
       
   614      Otherwise, the argument is supposed to be a string like object,
       
   615      and used directly (i.e. this is equivalent to sending #contents:)."
       
   616 
       
   617     self editValue:aStringOrObject selected:false
       
   618 !
       
   619 
       
   620 editValue:aStringOrObject selected:aBoolean
       
   621     "set the contents. If there is a converter, use it to convert
       
   622      the object into a printed representation.
       
   623      Otherwise, the argument is supposed to be a string like object,
       
   624      and used directly (i.e. this is equivalent to sending #contents:)."
       
   625 
       
   626     |text|
       
   627 
       
   628     converter notNil ifTrue:[
       
   629 	text := converter printStringFor:aStringOrObject
       
   630     ] ifFalse:[
       
   631 	text :=  aStringOrObject.
       
   632     ].
       
   633     self contents:text.
       
   634     aBoolean ifTrue:[
       
   635 	self selectFromLine:1 col:1 toLine:1 col:text size
       
   636     ]
       
   637 !
       
   638 
       
   639 converter:aConverter
       
   640     "set the converter. If non-nil,
       
   641      the converter is applied to the text to convert from the string
       
   642      representation to the actual object value and vice versa.
       
   643      The default converter is nil, meaning no-conversion
       
   644      (i.e. the edited object is the string itself."
       
   645 
       
   646     converter := aConverter
       
   647 !
       
   648 
       
   649 
       
   650 disable
       
   651     "disable the field; hide cursor and ignore input"
       
   652 
       
   653     enabled ifTrue:[
       
   654 	enabled := false.
       
   655 	self hideCursor
       
   656     ]
       
   657 !
       
   658 
       
   659 enableAction:aBlock
       
   660     "define an action to be evaluated when enabled by clicking upon"
       
   661 
       
   662     enableAction := aBlock
       
   663 !
       
   664 
       
   665 initialText:aString selected:aBoolean
       
   666     "set the initialText and select it if aBoolean is true"
       
   667 
       
   668     |len s|
       
   669 
       
   670     leftOffset := 0.
       
   671     self contents:(s := aString asString).
       
   672     aBoolean ifTrue:[
       
   673 	(len := s size) ~~ 0 ifTrue:[
       
   674 	    self selectFromLine:1 col:1 toLine:1 col:len
       
   675 	]
       
   676     ]
       
   677 !
       
   678 
       
   679 initialText:aString
       
   680     "set the initialText and select it"
       
   681 
       
   682     self initialText:aString selected:true
       
   683 ! !
       
   684 
       
   685 !EditField methodsFor:'editing'!
       
   686 
       
   687 paste:someText
       
   688     "redefined to force text to 1 line"
       
   689 
       
   690     super paste:someText.
       
   691     list size > 1 ifTrue:[
       
   692 	self deleteFromLine:2 toLine:(list size)
       
   693     ]
       
   694 ! !
       
   695 
       
   696 !EditField methodsFor:'cursor drawing'!
   837 !EditField methodsFor:'cursor drawing'!
   697 
   838 
   698 showCursor
   839 showCursor
   699     "make cursor visible if currently invisible - but only if this
   840     "make cursor visible if currently invisible - but only if this
   700      EditField is enabled"
   841      EditField is enabled"
   702     enabled ifTrue:[super showCursor]
   843     enabled ifTrue:[super showCursor]
   703 ! !
   844 ! !
   704 
   845 
   705 !EditField methodsFor:'cursor movement'!
   846 !EditField methodsFor:'cursor movement'!
   706 
   847 
       
   848 cursorCol:col
       
   849     "redefined to lock the cursor at the end, if I have a lngthLimit"
       
   850 
       
   851     |c sz|
       
   852 
       
   853     c := col.
       
   854     lengthLimit notNil ifTrue:[
       
   855 	sz := lengthLimit.
       
   856 	c > sz ifTrue:[
       
   857 	    c := sz+1.
       
   858 	]
       
   859     ].
       
   860     super cursorCol:c
       
   861 !
       
   862 
   707 cursorLine:line col:col
   863 cursorLine:line col:col
   708     "catch cursor movement"
   864     "catch cursor movement"
   709 
   865 
   710     super cursorLine:1 col:col
   866     super cursorLine:1 col:col
   711 !
   867 !
   718     ]
   874     ]
   719 ! !
   875 ! !
   720 
   876 
   721 !EditField methodsFor:'event handling'!
   877 !EditField methodsFor:'event handling'!
   722 
   878 
   723 accept
   879 keyPress:key x:x y:y
   724     "accept the fields contents - perform the leave action as if
   880     "if keyHandler is defined, pass input; otherwise check for leave
   725      return was pressed."
   881      keys"
   726 
   882 
   727     |value|
   883     |leave xCol newOffset oldWidth newWidth|
   728 
   884 
   729     value := self editValue.
   885     enabled ifFalse:[
   730     acceptAction notNil ifTrue:[
   886         ^ self
   731 	acceptAction value:value
   887     ].
   732     ].
   888 
   733 
   889     (key == #DeleteLine) ifTrue:[
   734     "model-view behavior"
   890         Smalltalk at:#CopyBuffer put:(self contents).
   735     self sendChangeMessageWith:value.
   891         self contents:''. ^ self
       
   892     ].
       
   893 
       
   894     (key == #Tab) ifTrue:[
       
   895         tabAction notNil ifTrue:[tabAction value. ^ self].
       
   896     ].
       
   897     (key == #Return) ifTrue:[
       
   898         crAction notNil ifTrue:[crAction value. ^ self].
       
   899     ].
       
   900     leave := leaveKeys includes:key.
       
   901     leave ifTrue:[
       
   902         leaveAction notNil ifTrue:[
       
   903             leaveAction value:key
       
   904         ].
       
   905 
       
   906         ((key == #Return and:[acceptOnReturn])
       
   907         or:[key ~~ #Return and:[acceptOnLeave]]) ifTrue:[
       
   908             self accept.
       
   909         ].
       
   910 
       
   911         x >= 0 ifTrue:[
       
   912             "
       
   913              let superview know about the leave ...
       
   914              This is a temporary kludge for the tableWidget -
       
   915              it is no clean coding style. Should make the tableWidget
       
   916              a proper model and handle it via the changed mechanism ....
       
   917             "
       
   918             (superView notNil and:[superView canHandle:key from:self]) ifTrue:[
       
   919                 superView keyPress:key x:x y:y.
       
   920             ].
       
   921         ].
       
   922         ^ self
       
   923     ].
       
   924 
       
   925     "
       
   926      ignore some keys (if not a leaveKey) ...
       
   927     "
       
   928     (key == #Find) ifTrue:[^self].
       
   929     (key == #FindNext) ifTrue:[^self].
       
   930     (key == #FindPrev) ifTrue:[^self].
       
   931     (key == #GotoLine) ifTrue:[^self].
       
   932 
       
   933     "
       
   934      a normal key - let superclass's method insert it
       
   935     "
       
   936     oldWidth := self widthOfContents.
       
   937     super keyPress:key x:x y:y.
       
   938 
       
   939     "
       
   940      for end-of-text, also move to end-of-line
       
   941     "
       
   942     key == #EndOfText ifTrue:[
       
   943         super keyPress:#EndOfLine x:x y:y.
       
   944     ].
       
   945     newWidth := self widthOfContents.
       
   946 
       
   947     "
       
   948      should (& can) we resize ?
       
   949     "
       
   950     xCol := (self xOfCol:cursorCol inVisibleLine:cursorLine) - leftOffset.
       
   951     (xCol > (width * (5/6))) ifTrue:[
       
   952         self changed:#preferedExtent
       
   953     ] ifFalse:[
       
   954         newWidth < (width * (1/6)) ifTrue:[
       
   955             self changed:#preferedExtent
       
   956         ]
       
   957     ].
       
   958 
       
   959     "
       
   960      did someone react ?
       
   961      (if not, we scroll horizontally)
       
   962     "
       
   963     xCol := (self xOfCol:cursorCol inVisibleLine:cursorLine) - leftOffset.
       
   964     (xCol > (width * (5/6))) ifTrue:[
       
   965         newOffset := leftOffset + (width // 2).
       
   966     ] ifFalse:[
       
   967         (xCol < (width * (1/6))) ifTrue:[
       
   968             newOffset := 0 max: leftOffset - (width // 2).
       
   969         ] ifFalse:[
       
   970             newOffset := leftOffset
       
   971         ]
       
   972     ].
       
   973     newOffset ~~ leftOffset ifTrue:[
       
   974         leftOffset := newOffset.
       
   975         self clear.
       
   976         self redraw
       
   977     ]
   736 !
   978 !
   737 
   979 
   738 buttonPress:button x:x y:y
   980 buttonPress:button x:x y:y
   739     "enable myself on mouse click"
   981     "enable myself on mouse click"
   740 
   982 
   747     ] ifTrue:[
   989     ] ifTrue:[
   748 	super buttonPress:button x:x y:y
   990 	super buttonPress:button x:x y:y
   749     ]
   991     ]
   750 !
   992 !
   751 
   993 
   752 keyPress:key x:x y:y
   994 focusIn
   753     "if keyHandler is defined, pass input; otherwise check for leave
   995     "got the explicit focus"
   754      keys"
       
   755 
       
   756     |leave xCol newOffset oldWidth newWidth|
       
   757 
   996 
   758     enabled ifFalse:[
   997     enabled ifFalse:[
   759 	^ self
   998 	enabled := true.
   760     ].
   999 	super focusIn.
   761 
  1000 	enableAction notNil ifTrue:[
   762     (key == #DeleteLine) ifTrue:[
  1001 	    enableAction value
   763 	Smalltalk at:#CopyBuffer put:(self contents).
       
   764 	self contents:''. ^ self
       
   765     ].
       
   766 
       
   767     (key == #Tab) ifTrue:[
       
   768 	tabAction notNil ifTrue:[tabAction value. ^ self].
       
   769     ].
       
   770     (key == #Return) ifTrue:[
       
   771 	crAction notNil ifTrue:[crAction value. ^ self].
       
   772     ].
       
   773     leave := leaveKeys includes:key.
       
   774     leave ifTrue:[
       
   775 	leaveAction notNil ifTrue:[
       
   776 	    leaveAction value:key
       
   777 	].
       
   778 
       
   779 	((key == #Return and:[acceptOnReturn])
       
   780 	or:[key ~~ #Return and:[acceptOnLeave]]) ifTrue:[
       
   781 	    self accept.
       
   782 	].
       
   783 
       
   784 	x >= 0 ifTrue:[
       
   785 	    "
       
   786 	     let superview know about the leave ...
       
   787 	     This is a temporary kludge for the tableWidget -
       
   788 	     it is no clean coding style. Should make the tableWidget
       
   789 	     a proper model and handle it via the changed mechanism ....
       
   790 	    "
       
   791 	    (superView notNil and:[superView canHandle:key from:self]) ifTrue:[
       
   792 		superView keyPress:key x:x y:y.
       
   793 	    ].
       
   794 	].
       
   795 	^ self
       
   796     ].
       
   797 
       
   798     "
       
   799      ignore some keys (if not a leaveKey) ...
       
   800     "
       
   801     (key == #Find) ifTrue:[^self].
       
   802     (key == #FindNext) ifTrue:[^self].
       
   803     (key == #FindPrev) ifTrue:[^self].
       
   804     (key == #GotoLine) ifTrue:[^self].
       
   805 
       
   806     "
       
   807      a normal key - let superclass's method insert it
       
   808     "
       
   809     oldWidth := self widthOfContents.
       
   810     super keyPress:key x:x y:y.
       
   811     newWidth := self widthOfContents.
       
   812 
       
   813     "
       
   814      should (& can) we resize ?
       
   815     "
       
   816     xCol := (self xOfCol:cursorCol inVisibleLine:cursorLine) - leftOffset.
       
   817     (xCol > (width * (5/6))) ifTrue:[
       
   818 	self changed:#preferedExtent
       
   819     ] ifFalse:[
       
   820 	newWidth < (width * (1/6)) ifTrue:[
       
   821 	    self changed:#preferedExtent
       
   822 	]
  1002 	]
   823     ].
  1003     ] ifTrue:[
   824 
  1004 	super focusIn
   825     "
  1005     ].
   826      did someone react ?
       
   827      (if not, we scroll horizontally)
       
   828     "
       
   829     xCol := (self xOfCol:cursorCol inVisibleLine:cursorLine) - leftOffset.
       
   830     (xCol > (width * (5/6))) ifTrue:[
       
   831 	newOffset := leftOffset + (width // 2).
       
   832     ] ifFalse:[
       
   833 	(xCol < (width * (1/6))) ifTrue:[
       
   834 	    newOffset := 0 max: leftOffset - (width // 2).
       
   835 	] ifFalse:[
       
   836 	    newOffset := leftOffset
       
   837 	]
       
   838     ].
       
   839     newOffset ~~ leftOffset ifTrue:[
       
   840 	leftOffset := newOffset.
       
   841 	self clear.
       
   842 	self redraw
       
   843     ]
       
   844 !
  1006 !
   845 
  1007 
   846 canHandle:aKey
  1008 canHandle:aKey
   847     "return true, if the receiver would like to handle aKey
  1009     "return true, if the receiver would like to handle aKey
   848      (usually from another view, when the receiver is part of
  1010      (usually from another view, when the receiver is part of
   849       a more complex dialog box).
  1011       a more complex dialog box).
   850      We do return true here, since the editfield will handle
  1012      We do return true here, since the editfield will handle
   851      all keys."
  1013      all keys.
       
  1014      OBSOLETE: dont use this anymore - its a leftover for the tableWidget"
   852 
  1015 
   853     ^ true
  1016     ^ true
   854 ! !
  1017 ! !
       
  1018 
       
  1019 !EditField methodsFor:'editing'!
       
  1020 
       
  1021 paste:someText
       
  1022     "redefined to force text to 1 line"
       
  1023 
       
  1024     super paste:someText.
       
  1025     list size > 1 ifTrue:[
       
  1026 	self deleteFromLine:2 toLine:(list size)
       
  1027     ]
       
  1028 ! !
       
  1029