Skip to content

Deprecated ‐ Add new properties to Pyramid

Yann LE GOFF edited this page Jul 31, 2024 · 1 revision

A property is an object used to display and modify part of an element. For example there is a property to modify the background of a BlElement and one to modify the visibility. All property are display on the right side panel of Pyramid. It contains a command and a spec presenter builder.

Together, we're going to implement the property to display and modify the value of the text in a BlTextElement.

The command

A command is used by Pyramid to obtain and change the value of an element. It is also used to save the state inside the history plugin.

A command inherits from the PyramidCommand class. To create a new command, you must implement at least 3 methods #canBeUsedFor:, #getValueFor: and #setValueFor:with:.

  • #canBeUsedFor: returns a Boolean if the command can be used.
  • #getValueFor: returns the value of an object property.
  • #setValueFor:with: modifies the value of an element.

It is sometimes necessary to modify the #commanInverse function.

  • #commanInverse returns the inverse of the current command. For example, the inverse command of add to a collection is remove from a collection.

BlTextElement command

We'll create an abstract class, PyramidBlocTextCommand, which will implement the #canBeUsedFor: method.

canBeUsedFor: anObject

	^ anObject class = BlTextElement or: [
		  anObject class inheritsFrom: BlTextElement ]
 

Next, we create the text change command: PyramidChangeTextCommand.

  • #getValueFor: returns a string of text from the BlTextElement.
  • #setValueFor:with: takes a string as argument and changes the text while retaining the properties (size, color, etc.) of the BlTextElement.
getValueFor: aBlTextElement

	^ aBlTextElement text asString
 
setValueFor: aBlTextElement with: aString

	| attributes rope |
	attributes := self getAttributesOf: aBlTextElement text.
	rope := aString asRopedText.
	rope attributes: attributes.

	aBlTextElement text: rope
 
getAttributesOf: aBlText

	^ aBlText attributesFinder attributesAndIndicesSuchThat: [ :a | true ]
 

Now we need to test what we've done. We create the PyramidChangeTextCommandTest class and use the trait TPyramidCommandTest on it to help us test the command we created.

TPyramidCommandTest has 2 methods that must be implemented: #command and #targetContainers.

  • #command returns the command to be tested.
  • #targetContainers returns a collection of PyramidCommandTestContainers.

PyramidCommandTestContainer` is a model used to contains object and there expected results for tests :

  • targetNoProp is an object in which we want to set the property.
  • prop is the value of a property.
  • targetWithProp is an object where the property is defined.

In our example, we have :

command

	^ PyramidChangeTextCommand new
  
targetContainers

	^ {
		  (PyramidCommandTestContainer
			   no: BlTextElement new
			   with: 'test1' asRopedText asElement
			   prop: 'test1').
		  (PyramidCommandTestContainer
			   no: 'hello' asRopedText asElement
			   with: 'test2' asRopedText asElement
			   prop: 'test2').
		  (PyramidCommandTestContainer
			   no: ('I am BOLD' asRopedText
					    bold;
					    attribute: (BlFontSizeAttribute size: 20);
					    attribute: (BlTextForegroundAttribute color: Color green);
					    yourself) asElement
			   with: ('test3' asRopedText
					    bold;
					    attribute: (BlFontSizeAttribute size: 20);
					    attribute: (BlTextForegroundAttribute color: Color green);
					    yourself) asElement
			   prop: 'test3') }
  

All tests are green. But in our case, we also want to test if the properties after setting a value are still the same (the collor didnt't change, or the font is still the same). So we're going to modify the method #testSetValueForWith.

testSetValueForWith

	| attributes |
	self targetsWithoutValuesAndValues do: [ :each |
		attributes := (each key text attributesFinder
			               attributesAndIndicesSuchThat: [ :a | true ])
			              collect: [ :a | a key ].
		self command setValueFor: each key with: each value.
		self assert: (self command getValueFor: each key) equals: each value.
		self
			assert:
				((each key text attributesFinder attributesAndIndicesSuchThat: [
					  :a | true ]) collect: [ :a | a key ])
			equals: attributes ]

The property

Now we need to create a view that can display our property and offer the possibility to the user to change it. This view will use the common API for the properties's views define in PyramidInputPresenter.

We want to have a simple text entry to enter the text. It already exist, it is called PyramidTextInputPresenter. So we do not need to create a custom one. If you want to create a custom one you must implements the PyramidInputPresenter API.

  • emptyValue sets the input to an empty value state where the property has no value.
  • mixedValues sets the input to a mixed values state where objects inside the collection have differents values.
  • value returns the value inside the input.
  • value: anObject sets the value of the input without triggering whenValueChangedDo block.
  • whenValueChangedDo: aBlock a block to trigger when the value is updated. As one argument who is the new value of the property.

To install the property we create a plugin.

Object << #PyramidBlocTextPlugin
	traits: {TPyramidPlugin};
	slots: {};
	tag: 'plugin-bloc-text';
	package: 'Pyramid-Bloc'
connectOn: aPyramidEditor

	aPyramidEditor propertiesManager addProperty: self class changeText.
changeText

	| property |
	property := PyramidProperty new
		            name: 'Text';
		            command: PyramidChangeTextCommand new;
		            pyramidInputPresenterClass: PyramidTextInputPresenter;
		            yourself.
	property pyramidInputPresenterModel help:
		'Change the value of the text'.
	^ property
Clone this wiki locally