Skip to content

Add a new plugin to Pyramid

Yann LE GOFF edited this page Aug 30, 2023 · 2 revisions

Add a plugin

Pyramid makes it easy to add plugins. A plugin is a module that adds new functionalities to the editor. It provides access to various information and systems linked to the editor, such as the list of root elements, the list of selected elements, the command execution system with integrated history, the properties presentation panel, the editor view, etc.

To add a plugin, simply create a new class and register it in the PyramidPluginManager singleton. The new class must implement 3 methods:

  • #addPanelsOn:, takes a PyramidWindow object as argument. Used to modify the editor view.
  • #configureBuilder:, takes a PyramidEditorBuilder object as argument. Used to configure the editor builder.
  • #connectOn:, takes a PyramidEditor object as argument. Used to Retrieve information from the editor.

Example

We want to add a plugin that display the executed commands in the Transcript. It can be toggle on and off with a button.

To create such plugin we need to follow this steps:

  1. Create the plugin class
  2. Register the class in the PyramidPluginManager singleton.
  3. Create the view object and / or class.
  4. Connect the view object to the Pyramid Editor View using #addPanelsOn: method.
  5. Create the business classes
  6. Connect the business object to the Pyramid Editor View using #connectOn: method.

1. Create the plugin class

We create a class named PyramidLogPlugin that uses the trait TPyramidPlugin. The trait contains the 3 necessary methods.

Object << #PyramidLogPlugin
	traits: {TPyramidPlugin};
	slots: { #logSwitchModel . #logSwitchButton . #logCommandExecutor  };
	tag: 'plugin-log';
	package: 'Pyramid'

2. Register the class in the PyramidPluginManager singleton.

To automaticly register the plugin to the PyramidPluginManager we can override the initialize class method. If the class is loaded in another Pharo image, it will be automaticly register to the PyramidPluginManager of the new image.

initialize
	"Add this method on class side to install the plugin when the class is loaded."

	PyramidPluginManager uniqueInstance addPlugin: self

3. Create the view object and / or class.

In our example the view consist of a button that can be toggle on and off. To do that we will create a model that indicate if the button is toggle or not. Then we will create a SpButtonPresenter and connect it to our model.

First, we create the model.

Object << #PyramidLogSwitchModel
	slots: { #toggle };
	tag: 'plugin-log';
	package: 'Pyramid'
PyramidLogSwitchModel >> initialize [
	toggle := true ].

PyramidLogSwitchModel >> toggle [
	^ toggle ].

PyramidLogSwitchModel >> toggle: anObject [
	toggle := anObject ].

Secodly, we create a button in the plugin.

PyramidLogPlugin>> logSwitchButton [
	^ logSwitchButton ].

PyramidLogPlugin>> logSwitchModel [
	^ logSwitchModel ].

PyramidLogPlugin>> initialize [
	logSwitchModel := PyramidLogSwitchModel new.
	logSwitchButton := SpButtonPresenter new.
	logSwitchButton action: [
		self logSwitchModel toggle: self logSwitchModel toggle not.
		self updateButtonIconAndHelp ].
	self updateButtonIconAndHelp ].

PyramidLogPlugin >> updateButtonIconAndHelp [
	self logSwitchButton icon: self logSwitchModel asIcon.
	self logSwitchButton adapter ifNotNil: [ :adapater |
		adapater widgetDo: [ :w |
			w setBalloonText: self logSwitchModel asHelp ] ] ].
PyramidLogSwitchModel >> asIcon [
	self toggle
		ifTrue: [ ^ self iconNamed: #checkboxSelected ]
		ifFalse: [ ^ self iconNamed: #checkboxUnselected ] ].

PyramidLogSwitchModel >> asHelp [
	self toggle
		ifTrue: [
			^ 'The command used will be displayed in the Transcript. Click to desactivate.' ]
		ifFalse: [
			^ 'The command used will not be displayed in the Transcript. Click to activate.' ] ].

4. Connect the view object to the Pyramid Editor View using #addPanelsOn: method.

We can change the view on 7 differents place in Pyramid.

  • topLeft, add a Button with an icon. Use a PyramidToolbarPanelBuilder with the method #makeButtonWithIcon:order:.
  • topCenter, add a Button with an icon. Use a PyramidToolbarPanelBuilder with the method #makeButtonWithIcon:order:.
  • topRight, add a Button with an icon. Use a PyramidToolbarPanelBuilder with the method #makeButtonWithIcon:order:.
  • space, add a BlSpace preview in the center (you should avoid to change this view). Use a PyramidPresenterPanelBuilder with the method #makePresenter:.
  • tabLeft, add a "tab" with a title, an icon and a SpPresenter to display. Use a PyramidTabPanelBuilder with the method #makeTab:label:icon:order:.
  • tabRight, add a "tab" with a title, an icon and a SpPresenter to display. Use a PyramidTabPanelBuilder with the method #makeTab:label:icon:order:.
  • selectionMenu, add a menu that will change according to the number of selected items. Use a PyramidMenuPanelBuilder with the methods #addGroupEmptySelection:order:, #addGroupSingleSelection:order: and #addGroupMultiSelection:order:.

In our example we want to add a button on the top-right. We need to change the #addPanelsOn: method.

PyramidLogPlugin >> addPanelsOn: aPyramidSimpleWindow [
	aPyramidSimpleWindow at: #topLeft addItem: [ :builder |
		builder makeButtonWithIcon: self logSwitchButton order: 200 ] ].

image

The order is used to choose the display order of the different added views.

Plugin #topLeft #topCenter #topRight
PyramidPluginDynamicLayout -9999 : Change left layout 9999 : Change right layout
PyramidSavePlugin 1 : Save
PyramidSavePlugin 2 : Save (project menu)
PyramidSpacePlugin 5 : refresh the BlSpace
PyramidHistoryPlugin 1 : undo
PyramidHistoryPlugin 2 : redo
Plugin #tabLeft #tabRight
(default) fisrt : Properties view
PyramidTreePlugin 1 : Tree
PyramidPluginSelection 1 : Playground

5. Create the business classes

The plugin will detect each time a command is executed by the PyramidMainCommandExecutor. The PyramidMainCommandExecutor can be decorated with a PyramidCommandExecutorDecorator so we will create a class that inherits it.

PyramidCommandExecutorDecorator << #PyramidLogCommandExecutor
	slots: {#logSwitchModel};
	tag: 'plugin-log';
	package: 'Pyramid'
PyramidLogCommandExecutor >> logSwitchButton [
	^ logSwitchButton ].

PyramidLogCommandExecutor >> logSwitchModel [
	^ logSwitchModel ].

PyramidLogCommandExecutor >> use: aCommand on: aCollection with: arguments [
	"This method should be implemented."

	"I use the command with the wrappee."

	self wrappee use: aCommand on: aCollection with: arguments.

	"I then print in the transcript the log only if the model allows it."
	self logSwitchModel toggle ifFalse: [ ^ self ].

	Transcript crShow: '[Pyramid] - Use of: <' , aCommand class name , '>
	with: ' , arguments printString , '
	on: ' , aCollection printString ].

6. Connect the business object to the Pyramid Editor View using #connectOn: method.

We now have to add the command executor decorator to the editor.

PyramidLogPlugin >> logCommandExecutor [
	^ logCommandExecutor ].

PyramidLogPlugin >> initialize [

	logSwitchModel := PyramidLogSwitchModel new.
	logCommandExecutor := PyramidLogCommandExecutor new.
	logSwitchButton := SpButtonPresenter new.

	logCommandExecutor logSwitchModel: logSwitchModel.

	logSwitchButton action: [
		self logSwitchModel toggle: self logSwitchModel toggle not.
		self updateButtonIconAndHelp ].
	self updateButtonIconAndHelp ].

PyramidLogPlugin >> connectOn: aPyramidEditor [

	| executor |
	executor := aPyramidEditor propertiesManager commandExecutor.
	self logCommandExecutor wrappee: executor.
	aPyramidEditor propertiesManager commandExecutor:
		self logCommandExecutor ].

Results

Pharo_2CFMYbyQt1