'From Squeak3.7 of ''4 September 2004'' [latest update: #5989] on 11 May 2008 at 10:18:59 pm'!
!classDefinition: #NameEntryLW category: #'LightWidgets-Examples'!
CompositeLW subclass: #NameEntryLW
	instanceVariableNames: 'entry name'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'LightWidgets-Examples'!

!NameEntryLW commentStamp: '<historical>' prior: 0!
NameEntryLW openExample

!

!classDefinition: #Person category: #'LightWidgets-Examples'!
Object subclass: #Person
	instanceVariableNames: 'name'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'LightWidgets-Examples'!
!classDefinition: #TextEntryFieldLW category: #'LightWidgets-Kernel'!
LightWidget subclass: #TextEntryFieldLW
	instanceVariableNames: 'stringPosition cursorBounds cursorPosition stringBounds selection selectionBounds selectionDirection entryMask color'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'LightWidgets-Kernel'!

!TextEntryFieldLW commentStamp: '<historical>' prior: 0!
This a text entry field for the lightWidgets framework.

It supports only a single font, color, and emphasis combination. 

It colaborates with an EntryFieldMask for validating it's input. 
For example: for allowing only an arbitrary number of digit characters as input you should use a mask like this EntryFieldMaskLW new beOneOrMoreDigits.


!


!LightWidget methodsFor: 'view of a model or target' stamp: 'jmv 5/11/2008 20:30'!
target: aModelOrView aspect: aSymbol action: anotherSymbol
	"As a view I show some aspect of a model (or target widget) (may use aspectAdaptor).
	I also can act on my model (or target widget), using some action (may use actionAdaptor)."
	
	self target: aModelOrView aspect: aSymbol aspectAdaptor: nil.
	self action: anotherSymbol; actionAdaptor: nil! !


!NameEntryLW methodsFor: 'updating' stamp: 'jmv 5/11/2008 20:30'!
updateEntry
	entry target: target aspect: #name action: #name:! !

!NameEntryLW methodsFor: 'updating' stamp: 'jmv 5/11/2008 20:16'!
updateName
	name target: target aspect:#name ! !

!NameEntryLW methodsFor: 'updating' stamp: 'jmv 5/11/2008 20:17'!
updateView
	self updateEntry; updateName ! !

!NameEntryLW methodsFor: 'initialization' stamp: 'jmv 5/11/2008 22:18'!
addSubmorphs
	| l |
	entry _ TextEntryFieldLW new.
	entry position: 30@15; extent:200@30.
	self addMorph: entry.

	l _ LabelLW label:  'Entered name:'.
	l position: 15@(15+30+10); extent: 200@25.
	self addMorph: l.

	name _ LabelLW new target:  target  aspect: #name.
	name position: 30@(15+30+10+50); extent: 200@25.
	self addMorph: name.
	
	self updateView
	
	! !

!NameEntryLW methodsFor: 'initialization' stamp: 'jmv 5/11/2008 20:16'!
initialize
	super initialize.
	bounds _ 10@10 extent: 250@150.
	self addSubmorphs. 
	! !


!NameEntryLW class methodsFor: 'examples' stamp: 'jmv 5/11/2008 20:18'!
openExample
	| model widget |
	model _ Person new.
	widget _ self new.
	widget beMainViewOn: model.
	widget openInWorld! !


!Person methodsFor: 'accessing' stamp: 'F Olivero 5/2/2008 05:22'!
name
	^name! !

!Person methodsFor: 'accessing' stamp: 'jmv 5/11/2008 20:18'!
name: aString
	name _ aString.
	self triggerEvent: #selfChanged ! !

!Person methodsFor: 'initialize-release' stamp: 'F Olivero 5/2/2008 05:23'!
initialize
	super initialize.
	name _ 'Unnamed'! !


!TextEntryFieldLW methodsFor: 'accessing'!
backgroundColor
	^ Color white! !

!TextEntryFieldLW methodsFor: 'accessing'!
borderColor
	^ Color black! !

!TextEntryFieldLW methodsFor: 'accessing' stamp: 'F Olivero 5/11/2008 18:16'!
borderWidth
	^ 2.0! !

!TextEntryFieldLW methodsFor: 'accessing'!
centered
	stringPosition _ #centered.
	self updateView
! !

!TextEntryFieldLW methodsFor: 'accessing'!
cursorColor
	^ Color green darker! !

!TextEntryFieldLW methodsFor: 'accessing' stamp: 'F Olivero 5/4/2008 01:27'!
entryMask: mask
	entryMask _  mask! !

!TextEntryFieldLW methodsFor: 'accessing'!
extent: aPoint
	super extent: aPoint.
	self updateView
	
	
	
! !

!TextEntryFieldLW methodsFor: 'accessing'!
font
	^ self defaultFont! !

!TextEntryFieldLW methodsFor: 'accessing'!
left
	stringPosition _ #left.
	self updateView
	
! !

!TextEntryFieldLW methodsFor: 'accessing'!
position: aPoint
	super position: aPoint.
	self updateView
	
	
! !

!TextEntryFieldLW methodsFor: 'accessing'!
right
	stringPosition _ #rigth.
	self updateView! !

!TextEntryFieldLW methodsFor: 'accessing'!
value
	(self target notNil and:[ aspect notNil] ) ifTrue:[ ^ self targetAspect] ifFalse:[ ^ '']! !

!TextEntryFieldLW methodsFor: 'testing'!
hasSelection
	^ selection extent  >= 0! !

!TextEntryFieldLW methodsFor: 'testing' stamp: 'jmv 5/11/2008 20:19'!
isValid
	^ self value notEmpty "and:[entryMask validate: self value]"! !

!TextEntryFieldLW methodsFor: 'user actions'!
backspaceEntered
	| h t string |
	string _ self value.
	(cursorPosition = 1 or:[string isEmpty]) ifTrue:[^self].
	self hasSelection 
		ifTrue:[ 
			h _ string copyFrom: 1 to: selection first -1.
			t _ string copyFrom: selection last + 1 to: string size.
			cursorPosition _  h size + 1.
			self clearSelection]
		ifFalse:[
			h _ string copyFrom: 1 to: cursorPosition - 2.
			t _  string copyFrom: cursorPosition to: string size.
			self moveCursorBack].
	string _ h , t.
	target  perform: action with:  string! !

!TextEntryFieldLW methodsFor: 'user actions'!
characterEntered:  char
	| string h t newValue valid |
	string _ self value.
	self hasSelection
		ifTrue:[ h _string copyFrom: 1 to: selection first -1. t _ string copyFrom: selection last to: string size. h _ h , (Array with: char)]
		ifFalse:[	h _ string. t _ Array with: char].
	newValue _ h , t.
	entryMask notNil
				ifTrue:[valid _ entryMask validate: newValue.  valid ifFalse:[ ^ Beeper beep]].
	cursorPosition _ cursorPosition + 1.	
	target  perform: action with:  newValue
	
	

	 
	
	! !

!TextEntryFieldLW methodsFor: 'user actions'!
clearSelection
	selection _ cursorPosition to: (cursorPosition -1).
	! !

!TextEntryFieldLW methodsFor: 'user actions'!
escapeEntered
	self clearSelection! !

!TextEntryFieldLW methodsFor: 'user actions' stamp: 'jmv 5/11/2008 20:24'!
moveCursorBack
	cursorPosition _ 1 max: cursorPosition - 1.
	self clearSelection.
	self updateView! !

!TextEntryFieldLW methodsFor: 'user actions' stamp: 'jmv 5/11/2008 20:24'!
moveCursorForth
	cursorPosition  = (self value size + 1) ifTrue:[ ^self].
	cursorPosition _ cursorPosition + 1.
	self clearSelection.
	self updateView
! !

!TextEntryFieldLW methodsFor: 'user actions' stamp: 'jmv 5/11/2008 20:24'!
moveCursorSelectionBack
	| end start |
	start _ selection first.
	end _ selection last.
	selectionDirection == #right 
			ifTrue:[ end _ end - 1]
			ifFalse:[	start _ 1 max:  start  - 1].
	selection _ start to: end.
	cursorPosition _ 1 max: cursorPosition - 1.
	self updateView
				
				! !

!TextEntryFieldLW methodsFor: 'user actions' stamp: 'jmv 5/11/2008 20:24'!
moveCursorSelectionForth
	| end start string |
	string _ self value.
	start _ selection first.
	end _ selection last.
	selectionDirection == #right 
			ifTrue:[ end _ string  value size  min: end + 1]
			ifFalse:[	start _ string size + 1 min:  start + 1].
	selection  _ start to: end.
	cursorPosition _ string size + 1 min: cursorPosition + 1.
	self updateView

				
				
! !

!TextEntryFieldLW methodsFor: 'user actions'!
moveCursorToBeggining
	cursorPosition _ 1.
	self updateView
! !

!TextEntryFieldLW methodsFor: 'user actions'!
moveCursorToEnd
	cursorPosition _ self value size + 1.
	self updateView
! !

!TextEntryFieldLW methodsFor: 'user actions'!
separatorEntered: char
	char = Character space
		ifTrue:[ self characterEntered: char] 
		ifFalse:[ Beeper beep]
! !

!TextEntryFieldLW methodsFor: 'events-processing' stamp: 'jmv 5/11/2008 20:25'!
keyStroke: evt
	| c |
	super  keyStroke: evt.
	evt commandKeyPressed  ifTrue:[^self].
	target isNil ifTrue:[ ^ self].
	c _ evt keyCharacter.
	( evt shiftPressed and:[ c isLetter not] ) ifTrue:[^ self selectionChanged: evt].
	c = Character arrowRight ifTrue:[^ self moveCursorForth].
	c = Character arrowLeft ifTrue:[ ^ self moveCursorBack].
	c = Character backspace ifTrue:[^ self backspaceEntered].
	c = Character delete ifTrue:[^self backspaceEntered].
	c = Character end ifTrue:[ ^ self moveCursorToEnd].
	c = Character home ifTrue:[ ^ self moveCursorToBeggining].
	c  = Character escape ifTrue:[^ self escapeEntered].
	c isSeparator ifTrue:[^self separatorEntered:c].	
	self characterEntered: c
	
! !

!TextEntryFieldLW methodsFor: 'events-processing'!
selectionChanged: evt
	| c string |
	c _ evt keyCharacter.
	string _ self value.
	self hasSelection 
		ifTrue:[
				c == Character arrowRight ifTrue:[self moveCursorSelectionForth].
				c == Character arrowLeft ifTrue:[ self moveCursorSelectionBack]]
		 ifFalse:[			
				(c == Character arrowRight and:[cursorPosition ~= (string size + 1)] )
					ifTrue:[ selectionDirection _ #right.  self moveCursorSelectionForth ].
				(c == Character arrowLeft and:[ cursorPosition ~= 1])
					ifTrue:[ selectionDirection _ #left. self moveCursorSelectionBack]] .
		
	c == Character end
		ifTrue:[	selectionDirection _ #right. 
				selection  _ selection first to: string size. 
				cursorPosition _ self value size + 1].
			
	c == Character home
		 ifTrue:[ selectionDirection _ #left. 
				selection  _ 1 to: selection last.
				 cursorPosition _ 1].
			
	 self updateView

		! !

!TextEntryFieldLW methodsFor: 'updating'!
updateCursor
	| orig ext font xOffset string |
	font _ self font.
	xOffset _ 0.
	string _ self value.
	(string notNil and:[string notEmpty ])
		ifTrue:[
			(0 to: cursorPosition -2 ) do:[:i|  xOffset _ xOffset + (font widthOf: (string at:i+1))]].	
	orig _ self stringPosition + (xOffset@0).
	ext _  2@ stringBounds extent y.
	cursorBounds _ orig extent: ext

! !

!TextEntryFieldLW methodsFor: 'updating'!
updateSelection
	| xOffset font  xExtent string |
	string _ self value.
	(string isNil | self hasSelection not) ifTrue:[ ^ self].
	font _ self font.
	xOffset _ 0.
	(1 to: selection first - 1) do:[:i| xOffset _  xOffset + (font widthOf: (string at:i))].
	xExtent _ 0.
	 selection do:[:i|  xExtent _ xExtent + (font widthOf: (string at:i))]. 
	selectionBounds _   (stringBounds origin +(xOffset@0) ) extent: (xExtent@ stringBounds extent y)   		
	! !

!TextEntryFieldLW methodsFor: 'updating'!
updateString
	stringBounds _ (self stringPosition extent: bounds extent - (2* self borderWidth))! !

!TextEntryFieldLW methodsFor: 'updating' stamp: 'F Olivero 5/11/2008 18:28'!
updateView
	self updateString; updateCursor; updateSelection.
	self changed! !

!TextEntryFieldLW methodsFor: 'event handling'!
handlesKeyboard: evt
	^ true! !

!TextEntryFieldLW methodsFor: 'private'!
stringPosition
	| xOffset yOffset bw |
	bw _ self borderWidth.
	stringPosition = #rigth ifTrue:[xOffset _  bounds extent x - bw  -  stringBounds extent x ].
	stringPosition = #left ifTrue:[xOffset _  bw + 1].
	stringPosition = #centered ifTrue:[	xOffset _ ((bounds extent x  - (2* bw )) /2) - (stringBounds extent  x/2) ].
	yOffset _bw.
	^  bounds origin  +  (xOffset@yOffset)	
		

	
! !

!TextEntryFieldLW methodsFor: 'private'!
wantsKeyboardFocusFor:  stringMorph
	^true! !

!TextEntryFieldLW methodsFor: 'initialization'!
initialize
	super initialize.
	bounds _ 20@20 extent: 100@(self font height + (2 * self borderWidth)).
	cursorPosition _ 1.
	selection _ 1 to: 0.
	stringPosition _ #left.
	color _ Color black! !

!TextEntryFieldLW methodsFor: 'drawing'!
drawOn: aCanvas
	| string leftX w cColor borderWidth  |
	borderWidth _ self borderWidth.
	aCanvas frameAndFillRectangle: bounds fillColor: self backgroundColor borderWidth: borderWidth borderColor: self borderColor.

	self isValid ifFalse:[aCanvas fillRectangle: bounds  color: (Color red alpha:0.4)].

	string _ self value.
	aCanvas drawString: string in: stringBounds font: self font color: color.

	self hasSelection  ifTrue:[ aCanvas fillRectangle: selectionBounds color: (Color green lighter alpha:0.5)].

	leftX _ cursorBounds origin x + (cursorBounds extent x / 2).
	w := 4.
	cColor :=  self cursorColor.
	1 to: w
		do: 
			[:i | 
				aCanvas fillRectangle: ((leftX - w + i - 1) @ (cursorBounds origin y + i - 1) 
								extent: ((w - i) * 2 + 3) @ 1)
						color: cColor.
					aCanvas fillRectangle: ((leftX - w + i - 1) @ (cursorBounds origin y + cursorBounds extent y - i) 
								extent: ((w - i) * 2 + 3) @ 1)
						color: cColor].
			aCanvas fillRectangle: cursorBounds color: cColor
	
			
	! !

NameEntryLW removeSelector: #updatePane!
