How do I add features to the Annotate Image Dialog
LiveCode for FM comes with some build in custom components, but what if these provide almost what you want but not quite?
You can add features to the built in custom components, or create your own custom components from scratch using the LiveCode IDE.
In this lesson we will extend the Annotate Image Dialog with the ability to add text labels to the image.
Make a copy of the Annotate Image Dialog
Each custom component is a LiveCode stack, that implements certain required features in order to run within FileMaker.
At the moment you can't clone built in custom components within the Workspace so start by downloading the attached stack.
Open the stack
Unzip the file and open 'stack.livecode' in the LiveCode IDE.
Rename the stack
LiveCode requires stacks that are open at the same time to have unique names so the first step is to rename the stack.
- Open the Stack Inspector from the Object Menu
- Set the Name to "annotateImageText"
Update the UI
The UI for the original Annotate Image Dialog has a button that allows the user to add a maker. Add a second button that will allow the user to add text.
- Ensure you are in Edit mode
- Add a button
- Open the Object Inspector
- Set the Name to "Add Text"
The button will call the AddText command, which will be implemented on the Card Script.
- Open the Object Script
- Set the button script to
on mouseUp AddText end mouseUp
The AddText command
The AddText command will create a field that the user can add text to.
- Open the Card Script
- Add the AddText command
command AddText local tLabel lock screen create field ("text" && (the number of fields of group "editor") + 1) in group "editor" set the width of it to 150 set the showBorder of it to false set the backgroundColor of it to 255,255,255 set the location of it to the location of image "image" set the behavior of it to the long id of button "Text Behavior" of me unlock screen end AddText
- Lock the screen to temporarily prevent screen updates. This allow you to make multiple changes without the user seeing each transition, all the changes are shown at once when the screen is unlocked.
- Create a new field. Each field is named 'text x'. To ensure the fields have unique names calculate the name of the new field using the current number of fields + 1.
- Set the width, border and background color off the field.
- Set the location of the field to the location of the image to center it.
- Set the behavior of the field. We will implement the behavior next.
Create the behavior for text fields
- Add a button to hold the behavior script
- Set the Name to "Text Behavior"
What is a behavior?
Behaviors are a method to create common functionality between objects without duplicating the scripts.
An object with a behavior set will act as though its script was set to the script of the behavior button or stack. If multiple objects share the same behavior, each will have its own set of script local variables. Any references to me, the owner of me, and so on, will resolve to the child object currently executing.
The behavior script
The fields/text areas have to behave differently in different states.
- Can be edited
- No border
- Can't be edited
- Can be moved around
The mouseDown handler
To allow fields to be moved around we will use the grab command. Locked (lockText property set to true) receive the mouseDown message so we can grab the field on mouseDown, the field will remain grabbed until the user releases the mouse button, at which point the control will receive a mouseUp message.
Open the script for the "Text Behavior" button and add the mouseDown handler.
on mouseDown grab me end mouseDown
The mouseUp handler
When the field receives the mouseUp message we want to make it editable. Add the mouseUp handler.
on mouseUp setEditable true end mouseUp
The closeField and exitField handlers
When you are stop editing the field, by focusing away from the field, we want to make the field non-editable.
When a field loses focus is receives one of two messages
- closeField - Sent to a field when the focus is being removed from that field and the field's content has changed.
- exitField - Sent to the field with the selection when the selection is being removed from the field, and its contents have not changed.
Add handler for these two messages.
on closeField setEditable false end closeField on exitField setEditable false end exitField
The setEditable command
The setEditable command changes the state of the field by setting properties. It takes one parameter, pEditable, which is either true or false.
In addition when a field is set to non-editable we make it tall enough to show all the text.
Add the setEditable command.
command setEditable pEditable if pEditable then // Set the properties of the field to make it editable set the showFocusBorder of me to true set the opaque of me to true set the lockText of me to false else // Set the properties of the field to make it non-editable set the showFocusBorder of me to false set the height of me to the formattedHeight of me set the opaque of me to false set the lockText of me to true end if end setEditable
Hide the Text Behavior button
The "Text Behavior" button should not be visible to the user so set its Visible property to false.
Allow the user to select away from a text field
Next we need to ensure users can click away from a text field.
A card can receive mouseUp messages, just like the markers and text fields. If a user clicks somewhere that is not a marker or text field we want to unfocus all the objects.
Add a mouseUp handler to the Card Script, this will be triggered if the user clicks on the card itself and will unfocus all the controls.
on mouseUp focus on nothing end mouseUp
Update the AddMarker command
Behaviors are referred to by long id, so if you change the name of a stack you need to ensure that any existing behaviors can still be resolved. Currently the behavior for marker is set on the template control, since we have changed the name of the stack this will need updated.
We will update the AddMarker command to set the behavior when we create new markers.
Open the Card Script from the Object menu and add a line of code that set the behavior of the new marker.
command AddMarker local tMarker repeat with tMarker = 1 to the number of groups of group "editor" if the hidden of group tMarker of group "editor" then show group tMarker of group "editor" at the location of image "image" exit AddMarker end if end repeat lock screen clone group "Marker 1" of group "editor" set the location of it to the location of image "image" set the label of button "marker number" of it to the number of groups of group "editor" set the name of it to ("Marker" && the number of groups of group "editor") set the behavior of it to the long id of button "Marker Behavior" of me end AddMarker
Update the stack script
We also need to update the stack script to load this plugin and to store and load any text along with the image.
Open the Stack Script, we will be updating the FileMakerAction handler.
Note: The FileMakerAction handler is called whenever the component is called from FileMaker via LC.
Load the plugin
Firstly we will update the code that makes the plugin visible. This is done using the modal command. We need to update that line to launch the "annotateImageText" stack.
Update the code to
modal stack "annotateimagetext"
Storing text field details
Next we will store any text fields. Find the section of the stack script that stores the maker information, it should be lines 66 to 72
repeat with tMarker = 1 to the number of groups of group "editor" ... end repeat
We need to do the same for text fields, add this code after the marker saving code.
For makers we only store the location, for text fields we also need to store the text.
repeat with tText = 1 to the number of fields of group "editor" if the visible of field tText of group "editor" then put the location of field tText of group "editor" into tNewFileDataA["textfields"][tText]["location"] put the text of field tText of group "editor" into tNewFileDataA["textfields"][tText]["text"] add the hScroll of group "scroller" to item 1 of tNewFileDataA["textfields"][tText]["location"] add the vScroll of group "scroller" to item 2 of tNewFileDataA["textfields"][tText]["location"] end if end repeat
Loading text field details
Next we need to load the text field information that is stored along with the image.
Go to the section of the stack script that loads the marker information. It should end on line 55.
We need to do the same for text fields
- If there is not a field create it
- Set the location of the field
Firstly we find out how many text fields there are. Add the variable declaration and code to the section that gets the number of markers.
local tTotalMarkers, tTotalTextFields put max(the number of elements of tFileDataA["markers"], the number of groups of group "editor") into tTotalMarkers put max(the number of elements of tFileDataA["textfields"], the number of groups of group "editor") into tTotalTextFields
Then add this code after the marker loading code.
local tTextField repeat with tTextField = 1 to tTotalTextFields if there is not a field tText of group "editor" then create field tText in group "editor" set the width of it to 150 set the showBorder of it to false set the opaque of it to false set the lockText of it to true set the text of it to tFileDataA["textfields"][tText]["text"] end if if tFileDataA["textfields"][tText]["location"] is not empty then show field tText of group "editor" at tFileDataA["textfields"][tText]["location"] else hide field tText of group "editor" end if end repeat
Adding the stack to FileMaker as a Custom Component
Now we are finished updating the stack in LiveCode we want to add it to FileMaker as a custom component.
- Start up FileMaker
- Open the LiveCode for FM solution
- Click the "Custom Components" button to open the Workspace
- Click the "+" button
- Navigate to your stack and select it
- Set the name of the custom component to "annotateImageText"
The "annotateImageText" component will appear in the list and will be automatically selected. When a new custom component is added a default guide is created for it. You can update the guide, which is written in Markdown, by clicking the edit button which opens the folder containing the custom component and editing the 'guide.md' file in the folder.
When you are done click the "Close" button to return to the solution.
Testing the Dialog
To test the dialog create a new solution that contains a container and a button that executes
- Drag an image into the container
- Click the button to show the dialog
- Click the "Add Text" button
- An editbable field is created
- Add some text to the field
Click away from the field to stop editing
- Click and hold on the field to drag it to the location you want
- Release the mouse button to place the field
- Click away from the field
Click the "Done" button to return to the solution. The container will be updated with the annotated image.
There are lots of ways you could take this custom component further
- Allow the user to add graphics
- circle to highlight certain areas
- Provide formatting options
- text color
- marker border color
- marker background color