-
Notifications
You must be signed in to change notification settings - Fork 0
Creating Custom Effects
The following page assumes knowledge of the Python programming language.
For the user, an effect is something that is executed when a button associated with that effect is clicked. This can range from simply sending a message directly to a connected device, to presenting the user a colour picker dialogue to change the colour displayed on the connected device.
In essence, an effect will take some user input from a popup window, process that input into a valid message, and finally send that created message to a connected device. The user input is completely optional and the effect can instead process a user-defined payload associated with a button.
Internally, an effect is a file that contains a single class, that class storing the logic for the effect.
An effect must satisfy the following conditions:
- It must be inside a file with the same name as the class.
- It must contain an
__init__method that takes the parametersself, message, out_type=None, *args, **kwargs. - It must contain a static method
effectDatathat takes exactly 0 parameters.
This method is called during the effect discovery phase. Currently, this method must return an effect name, i.e. a user-readable label for the effect. This method must be static.
This method is called whenever the user selects a button with this effect assigned to it.
Unlike the the effectData method, an object is created whenever an effect is called.
In essence, this method is the entry point for running the effect.
Each effect has 2 mandatory parameters: message and out_type.
message is the user-defined payload assigned to the button calling the effect, and is passed as a string.
out_type is the user-defined message type assigned to the button calling the effect, and is passed as a string.
At the end of the day, the goal of an effect is to send some sort of message to a connected device.
To send an effect, you'll first need to import the communications runner module.
from src import run_comm as commTo actually send the message, you'll need to run the run function with correct parameters.
comm.run('write', message, out_type)Here, we're just passing the message and out_type parameters we accepted in __init__ directly to run.
The first string 'write' just says that we want to write a message to a device (it's interpreted as an attribute name when it comes to running the current communicator module).
In this first example, we'll create an effect that just send the button payload directly to the connected device.
Firstly, we'll need to create a class with a constructor. This constructor will just be used to store the button payload and button message type, and send the message.
from src import run_comm as comm
class MessageDirect():
def __init__(self, message, out_type=None, *args, **kwargs):
self.message = message
self.out_type = out_type
self.sendMessage()We'll make a new method sendMessage to actually send the message to a connected device.
def sendMessage(self):
comm.run('write', self.message, self.out_type)Finally, we need to add the effectData method.
@staticmethod
def effectData():
effect_name = 'Direct Message'
return effect_nameThat's it! Now when the user goes to make a new button, they'll have the option of creating a 'Direct Message' effect, and clicking on this button will call our effect.
In this next example, we'll show the user a colour picker dialogue and tell a connected device to display our colour.
We'll start this effect similarly to the last one, but with 2 differences this time:
- The button payload does not matter since the message is based on the colours picked by the user.
- The
__globals__module is imported to use the global colour picker.
from src import __globals__
from src import run_comm as comm
class SolidColour():
def __init__(self, message, out_type=None, *args, **kwargs):
self.out_type = out_type
self.getColor()Next, we need to add the logic to display the colour picker.
def getColor(self):
self.color = None
__globals__.colour_picker.colorSelected.connect(self.updateColor)
__globals__.colour_picker.exec()Here, we're just telling the colour picker to run the method updateColor (which we'll create a bit later) whenever the user selects a colour. We then run colour_picker.exec to show the popup. This is a blocking call, so the rest of the getColor method will not run until the user closes the window.
After the user closes the popup, we want to now send the data to a connected device. We'll add this to the end of our getColor method.
if self.color is not None:
self.color = list(self.color)
self.message = f'{self.color[0]},{self.color[1]},{self.color[2]}'
comm.run('write', f'solidcolor,{self.message}', self.out_type)The first part of sending the message is making sure the user actually selected something. Since we initialise color as None, if the user never selected a colour, the updateColor method will have never run, meaning color will have never changed and will remain None. We don't have to do anything if the user didn't select a colour.
If the user did select a colour, we take the first three elements of that list - R, G, B. We need to convert a string. For example, if the selected colour was 40, 60, 80, we need to create a string in the end solidcolor,40,60,80, where solidcolor is the name of the effect. The message type will handle formatting this string into a valid message for the selected device.
Now we need to implement the updateColor method.
def updateColor(self):
self.color = __globals__.colour_picker.currentColor().getRgb()This method just takes the RGB values of the currently selected colour from the popup window and updates color to that value.
Finally, we need to add the effectData method.
@staticmethod
def effectData():
effect_name = 'Solid Colour'
return effect_nameWith that, we now have an effect that, when added to a button and that button pressed, will display a dialogue prompting the user to select a colour. If the user selects a colour and clicks the 'ok' button, the colour data will be sent to the selected device. Otherwise if the user exits the window without selecting a colour, nothing happens.
Once you've created an effect and ensured the file name matches the class name, you'll need to place it in src/ui/effects/effect. That's it!. Importing this effect is handled automatically on startup.
If you're finding errors when trying to run an effect, it may help to see how it's imported in src/ui/effects/effects.py.
FreeRGB | License | Code of Conduct | Contributing | Wiki | Code