How to create reusable widgets
This guide explains how you can create reusable "named" widgets that you can use again and again on multiple display slides. This saves you from having to copy-and-paste the same widget (or sets of widgets) into multiple slide configurations, it makes it easy to update and fine-tune your widget config since you only have to change it in one place, and it lets you add individual widgets to the display that will show up regardless of what slide is currently showing.
1. Understanding widgets
Before we look at how to create reusable widgets, let's look at how regular widgets work in MPF.
You probably know that you can have a slides:
section of your config
(either machine-wide or mode-specific configs), and when you define a
slide, you can specify what widgets are on that slide, like this:
slides:
my_slide:
widgets:
- type: text
text: HELLO!
- type: text
x: 0
font_size: 5
text: YAY PINBALL
- type: image
image: background1
In the example above, the slide called my_slide has three widgets--two text widgets and a background image. (Remember that the "z order" or "layer" of widgets is top-to-bottom, so the HELLO! widget is on top, then YAY PINBALL is next, and they're both on top of the background1 image.
These three widgets are permanently attached to the slide called my_slide. There's no way to reuse them on any other slides.
2. Creating reusable widgets
But what if you had a widget you wanted to use on multiple slides? For example, maybe you have a widget with some animations that comes on the display when a certain shot is made, and you want that widget to appear on any slide (whichever slide happens to be showing at that time).
The way to do that is to create a "named" widget that's reusable. You
do that in the widgets:
section of your config. (This can be either a
machine-wide or a mode config file.)
For example:
widgets:
laughing_jackal:
- type: image
image: jackal
Now you have a widget defined called laughing_jackal that you can add to any slide. (Note that this example is simple, but any widget type with any widget settings can be defined here, including positioning, colors, animations, etc.
The only "catch" is that the list of widget names is global across MPF. So even though you can define widgets in both the machine-wide or the mode config files, named widgets are processed when MPF starts up, so don't use the same name twice since whichever one loads second will overwrite the first one.
3. Using your named widget
Now that you have a widget defined, how do you add it to a slide?
That's done via the "widget" config player, which means you can add a
widget_player:
section to a config file to trigger it based on an
event, or you can add it via the widgets:
section of a show step. (All
the examples in this guide will be based on the widget_player:
section
of a config file, but you can use them all in show steps too. Just use
them in a widgets:
section of a show step and do not include the event
name.
There are several options you can use in the widget player, depending on how you and where you want to show your widget (which display, which slide, etc.)
"Express" config
If you just want to add your widget to whichever slide is current on the default display, you can use the "express" config, like this:
#! widgets:
#! laughing_jackal: []
#! another_widget: []
widget_player:
some_event: laughing_jackal
some_other_event: another_widget
With the config above, when the event some_event is posted, the widget called laughing_jackal will be added to the current slide on the default display. Notice that you can add multiple entries here for different widgets and different events.
This widget is added with whatever settings you defined for it in the
widgets:
section of your config. It's all pretty straightforward,
though you might have to play with the z:
setting (the layer) to get
it to show up. (For example, if your current slide has a full size
background, you'd want to configure your widget with a z:
setting
that's a higher priority so it shows up on top of the background
image.)
Adding a widget to a specific slide (by slide)
If you want to build a slide and include a reusable widget, you can
reference the widget's name in your slide config by declaring widget:
instead of type:
.
widgets:
jackpot_value_widget:
- type: text
text: (jackpot_total)
style: medium
slides:
hero_hurryup:
- type: text
text: "Hurry Up!"
- type: text
text: "Jackpot:"
- widget: jackpot_value_widget
slide_player:
show_hero_slide: hero_hurryup
##! test
#! post show_hero_slide
#! advance_time_and_run .1
#! assert_text_on_top_slide "Hurry Up!"
Adding a widget to a specific slide (by event)
If you want to add your widget to a particular slide (versus whatever
slide happens to be showing at the moment), you can do so by specifying
that slide name in the widget_player:
. For example:
#! widgets:
#! laughing_jackal: []
widget_player:
some_event: # event that will trigger this widget to show
laughing_jackal: # widget you want to show
slide: my_slide
In the example above, when the event some_event is posted, the widget laughing_jackal will be added to the slide called my_slide. If my_slide is the current active slide on the display, you'll see the widget appear. If that slide is not being shown, the widget will still be added, and it will be there the next time that slide is shown.
Remember you can add as many events and widgets as you want to the
widget_player:
section of your config, and you can even mix-and-match
formats, like this:
#! widgets:
#! laughing_jackal: []
#! another_widget: []
widget_player:
some_event:
laughing_jackal:
slide: my_slide
some_other_event: another_widget
Adding a widget to a specific display target
Rather than specifying a particular slide to add your widget to, you can target a display, and the widget will be added "on top" of whatever slide is currently being shown:
#! widgets:
#! laughing_jackal: []
#! displays:
#! display1:
#! width: 1366
#! height: 768
#! default: true
widget_player:
some_event:
laughing_jackal:
target: display1
Remember in MPF, display targets are the names of a display (dmd, window, etc.).
More details about this are in the Widget layers, z-order, & parent frames guide.
Overriding named widget settings
When you create your named widget, it contains a bunch of settings that are used to add it to a slide. (That's sort of the whole point.)
However sometimes it's useful to be able to override or add additional
settings at play time. You can do this in the widget_settings:
section
of the widget_player:
in a config file or the widgets:
section of a
show step.
For example, if you use a widget for the tilt warning like in the previous example, you'd probably want that widget to be removed after a few seconds, which you could do like this:
#! widgets:
#! tilt_warning: []
widget_player:
tilt_warning: # event
tilt_warning: # widget name
widget_settings: # additional settings to be added / updated
expire: 2s
(Technically speaking, if you were going to show a tilt warning widget,
you'd probably also want to play a sound and maybe flash all the lights
on the playfield, so in your real game you're probably actually create
a show to do this and then play it via the show_player:
section of
your config and include the widget in the widgets:
section of the
show, but you get the idea.)
You can also set the expiration time of a widget when you define the
widget in the widgets:
section of the config. See the config file
reference for details.
You can add/update any setting for the widget (color, text, position, animations, widget_styles, z (layer), etc.)
Removing widgets
You can also use the widget player to remove named widgets from a slide
that had been previous added. To do this, just add an action: remove
setting to the widget player, like this:
#! widgets:
#! laughing_jackal: []
widget_player:
show_jackal: laughing_jackal
hide_jackal:
laughing_jackal:
action: remove
The config above will add the laughing_jackal to the current slide on the default display when the event show_jackal is posted, and then it will remove it when the event hide_jackal is posted.
Creating named groups of widgets
All of the examples in this guide showed using a single widget as named widget. But you can actually define multiple widgets in a named widget (essentially meaning that your named widget is really a named group of widgets. For example:
widgets:
widget3:
- type: text
text: HI
color: ff0000
font_size: 100
- type: text
text: THERE
color: 00ff66
font_size: 100
- type: text
text: EVERYONE!
color: ff00ff
font_size: 100
You play, show, or hide this "widget" in the same way as every other example in this guide, except in this case, playing widget3 will actually add all three widgets to the slide. (Again you can play with z-order / layering, and remember that each widget (even in a multi-widget group) can have its own z-order settings.
Putting it all together, these are the basics of using named widgets in MPF. The important takeaways are:
- Widget names are global, so don't use the same name twice.
- Everything here can be done in either the
widget_player:
section of a config file or thewidgets:
section of a show step. - All widget options are valid, including keys, animations, expiration, styles, positioning, z-ordering, colors, transparencies, padding, etc.
- When "playing" a widget, you can target a display or a slide.
- Once a widget is "played" and added to a slide, it becomes just another widget on that slide. The fact that it was put there by the widget player doesn't matter.
Adding multiple named widgets in one event
You can also add multiple named widgets from a single event. This is nice if you want to add widgets to multiple displays or slides at the same time. For example:
#! widgets:
#! widget1: []
#! widget2: []
#! displays:
#! lcd:
#! width: 1366
#! height: 768
#! default: true
#! dmd:
#! width: 640
#! height: 480
widget_player:
some_event:
widget1:
target: dmd
widget2:
target: lcd
Note that if you do this, the structure of YAML requires that you have
at least one setting under each widget name, so you can just add a
target:
or action: add
if you don't want to change or set anything
else in the widget.
Dynamically choosing a widget based on variables
You can use a placeholder widget in a slide to dynamically choose any reusable widget for that slide, depending on an event parameter or player variable.
To create a placeholder widget in the slide, use the widget:
setting
with the standard
dynamic text formatting.
For example, using the player variable "hero_class" to pick a text image (but could be an image widget as well):
widgets:
hero_portrait_rogue:
- type: text
text: "Portrait Rogue"
hero_portrait_bard:
- type: text
text: "Portrait Bard"
hero_portrait_mage:
- type: text
text: "Portrait Mage"
slides:
hero_slide:
- type: text
text: (player|name)
- type: text
text: Level (player|level)
- widget: hero_portrait_(current_player.hero_class)
slide_player:
show_hero_slide: hero_slide
##! mode: base
variable_player:
set_var_rogue:
hero_class:
action: set
string: "rogue"
##! test
#! start_game
#! start_mode base
#! post set_var_rogue
#! advance_time_and_run .1
#! post show_hero_slide
#! advance_time_and_run .1
#! assert_text_on_top_slide "Portrait Rogue"
You can also use the parameters of an event to determine the widget to include. In the following example from a game with different multiballs, the event mball_lock_lit might post with either "angel" or "demon" as the mball_name parameter.
slide_player:
mball_lock_lit: mball_lock_slide
slides:
mball_lock_slide:
widgets:
- type: text
text: Lock is Lit
- widget: lock_lit_(mball_name)
widgets:
lock_lit_angel:
- type: text
text: Angels Anarchy
- type: image
image: bg_locklit_angels
lock_lit_demon:
- type: text
text: Demons Derby
- type: image
image: bg_locklit_demons
Something missing or wrong? You can fix it!
This website is edited by people like you! Is something wrong or missing? Is something out of date, or can you explain it better?
Please help us! You can fix it yourself and be an official "open source" contributor!
It's easy! See our Beginner's guide to editing the docs.
Page navigation via the keyboard: < >
You can navigate this site via the keyboard. There are two modes:
General navigation, when search is not focused:
- F , S , / : open search dialog
- P , , : go to previous page
- N , . : go to next page
While using the search function:
- Down , Up : select next / previous result
- Esc , Tab : close search
- Enter : go to highlighted page in the results