Frequently Asked Questions
Which programming languages can I use with Playbit?
Currently, C and Python. When creating a project in DevXP, there is a template selection to pick the language.
Our bindings are generated automatically from a single source, and we'd like to support more languages in the future. We may also open source the bindings generator and its source, so that people can contribute support for new languages.
How do I log all the fields of a structure?
Use the PBLog-
functions. For example,
PBLogPBMessage(message);
How do I make an element fill its parent?
Pass PBElement_H_FILL, PBElement_V_FILL or both when creating the element.
This flags make the element fill the remaining space its in direct parent. They do not, however, make the parent fill the remaining space of its parent. Therefore, you may need to pass these flags on the parent element as well (as its parent, and so on).
Note that the root element added to the window (of which there can only be one) always fills the entire window.
How do I make a layout column or row scrollable?
Wrap it in a PBScrollView. See PBScrollViewCreate for an code example.
How do I programatically scroll to the bottom of a scroll view?
Call PBScrollViewScrollTo with a sufficiently large value for the position.
PBScrollViewGetState will give you the current maximum position, but if you've added any new elements during this event cycle it may be out of date. You can also manually ask the content to compute its size with PBElementMeasure.
How do I attach context data to an element?
See PBElementSetUserDataInt and PBElementSetUserDataPtr.
How do I prevent a window from filling the height of the screen?
Include PBWindow_NO_RESIZING in the flags
of PBWindowCreationOptions.
How do I add space around an element?
Wrap it in a layout column, and set its insets
appropriately. For example,
AddMyElement(parent, flags, ...);
becomes
AddMyElement(PBLayoutColumnAdd(parent, 0, 0,
PB_RECT_4(leftSpaceDp, rightSpaceDp, topSpaceDp, bottomSpaceDp)), flags, ...);
How do I add space within an element?
To add space between an element and its child elements, set its insets
. For example,
PBElementSetPropertyRectangle(element, PBElementProperty_INSETS,
PB_RECT_4(leftSpaceDp, rightSpaceDp, topSpaceDp, bottomSpaceDp), NULL);
What is an element message handler?
PBElementCreate creates a new custom element. It's like PBButtonCreate, PBLogViewAdd etc, but it takes a message handler parameter, a function pointer.
The message handlers is sent messages like PBMsg_KEY_DOWN and PBMsg_MOUSE_MOVE when events relevant to that element occur. It's also sent messages when the system wants to request certain things of the element.
For example, the message PBMsg_GET_CURSOR is sent when the system wants to know what cursor image to use for that element. The message handler fills out the message->getCursor.cursorID value in response.
You can also set a "user" message handler for standard elements using PBElementSetUserMessageHandler. This allows your application to intercept messages that otherwise would be handled by the system. Returning a non-zero from this callback will prevent the original message handler from receiving the message.
How do I request an animation frame?
Call PBElementRequestAnimationFrame. The element will then receive a PBMsg_ANIMATION_FRAME on the next animation frame in its message handler (see PBElementSetUserMessageHandler).
On receiving this message, you'll likely want to ask the element to repaint with PBElementRepaintAll and then request another animation frame.
How do I change the text styling of a table view item?
Handle the PBMsg_TABLE_GET_DOCUMENT in addition to the PBMsg_TABLE_GET_STRING.
There are various functions which create a PBTextDocument, such as PBTextDocumentCreateWithPositionedAttributes.
How do I change the text styling of a button?
Use PBButtonSetTextStyle. A text style can be created with PBTextStyleCreate.
When are user interface elements drawn?
After processing each event (e.g. key press, animation update, application startup etc.), the system checks if any user elements have been marked to be repainted. If so, these elements will be painted; any elements these overlap may also be painted if needed. Elements with the PBElement_CUSTOM_PAINT will receive PBMsg_CUSTOM_PAINT messages at this point.
An element is marked to be repainted when:
- It is created.
- It is moved during UI layout.
- A manual call is made to PBElementRepaintAll or PBElementRepaintPartial.
Standard elements, such as buttons and text displays, automatically call the explicit repaint functions when their content changes. For example, when your application calls PBButtonSetLabel the system will automatically call the necessary repaint functions.
Why is my element not receiving keyboard input?
Keyboard events are sent to the focused element. To focus an element, call PBElementFocus.
See Input Event Routing for a detailed explanation.
Why is my element not receiving mouse input?
The element flags PBElement_INPUT_MOUSE_LEFT, PBElement_INPUT_MOUSE_MIDDLE and PBElement_INPUT_MOUSE_RIGHT are used to receive mouse input events on an element. If an element does not have the flag for a given mouse button set, then those inputs are passed to its layout parent in the element hierarchy.
See Input Event Routing for a detailed explanation.
Why is my element not showing up?
An element may not be shown because it, or one of its layout ancestors, are hidden. An element is hidden by setting the PBElement_HIDDEN flag when it's created, or by calling the PBElementSetHidden function.
An element may not be shown because the automatic layout algorithm gave it no space. Try explicitly giving it a size:
PBElementSetPropertyF32(element, PBElementProperty_WIDTH, 100, NULL);
PBElementSetPropertyF32(element, PBElementProperty_HEIGHT, 100, NULL);
If you're trying to make an element that fills the space of its parent using the PBElement_H_FILL and PBElement_V_FILL flags, check that:
- both flags are specified if they need to be;
- the parent also has non-zero size; you may need to set the fill flags on all layout ancestors leading up to the window.
You can use the UI inspector to see a breakdown of how an element's size was determined. Click the app's menu (in the top-left corner) and select "UI Inspector". (This menu item is only shown if "Show debugging options" is enabled in Settings.)
How do I make a canvas element that I can draw on?
Playbit is not like HTML so there is no concept of "a canvas". All elements in a window are able to perform custom painting.
If an element does not have the PBElement_CUSTOM_PAINT flag, then it is painted by the system. Its appearance can either be a pre-defined style (see PBElementSetStyle), or it can be defined by setting various properties (see the PBElementSetProperty* functions).
If an element has the PBElement_CUSTOM_PAINT flag, then the system sends PBMsg_CUSTOM_PAINT messages to its message handler when it needs to be painted. This message is sent 3 times, one for each draw layer depth. message->customPaint.painter
contains a PBPainter which is used to paint the element's contents.
The PBMsg_CUSTOM_PAINT message is sent in various situations.
- If PBElementRepaintAll is called on the element, then the system will certainly need to paint the element.
- If PBElementRepaintAll is called on a different element that overlaps this element, it may also need to be painted.
The system is also allowed to send this message whenever it likes. e.g. to take a screenshot.
When you're painting an element in a PBMsg_CUSTOM_PAINT message, there is no need to fill in the background at the start to clear out the old image you drew. This is because there will always be some element behind your element that fills in the background. When you call PBElementRepaintAll with your element, the system will also repaint elements in the areas that overlap your element. In particular, this includes the elements behind it. Therefore the background will also be cleared out by the time your element is painted.
How do I retain the image I have drawn on a custom-painted element between repaints?
The output of the draw commands you issue when painting an element are not saved. There is no bitmap or anything kept around after drawing. If the element needs to be painted again for whatever reason, it has to send another PBMsg_CUSTOM_PAINT message to the element because it hasn't retained that information.
For most apps, there will only ever be one PBRenderSurface, and that's the render surface owned by the window. When your element receives the paint message, the painter parameter will be painting onto a sub-region of this surface. The sub-region is determined by the bounds of the element. The painter also has a transformation applied ot it so that the coordinate (0,0) is the top-left of the element.
If you want to keep a drawn bitmap around across a frame, or it is necessary for some complex drawing operation, then you can create a PBRenderSurface with the PBRenderSurfaceCreateCompatibleWithElement function. This function takes as parameter an element that the surface is "compatible" with. This should be element that the surface is used with. This information is needed because multiple windows in the same app could be on different displays, which could have different characteristics like scale factor and color space.
To draw on the render surface, use PBRenderSurfaceBeginPainting (this gives you a PBPainter) and to destroy the render surface, use PBRenderSurfaceRelease.
The render surface can then be drawn onto another painter with PBDrawRenderSurface.
Between frames, you should call the PBRenderSurfaceGetContentsLostFlag to check if the contents of a render surface has been lost. This can happen in various situations, whenever the graphics card had to lose the contents of surface.
What is a "dp" and what causes the scale factor to change?
The scale factor is a user setting. In the Settings app, there is a scale factor slider. It's useful for high density displays and as an accessibility option.
At 100% scale factor, 1 dp = 1 px. At 200% scale factor, 1 dp = 2 px.
How do I center an element in a column or row?
If you want to horizontally center an element in a column (PBLayoutColumnCreate), or if you want to vertically center an element in a row (PBLayoutRowCreate), then you're already done! This is the default.
If you want to horizontally center an element in a row, add two additional elements, one before it and one after it. Pass the PBElement_H_FILL flag to these elements. These two additional elements will distribute the remaining space in the row between themselves evenly, thus causing the other elements to be in the center.
If you want to vertically center an element in a column, the process is similar. The flag to pass to the additional elements is PBElement_V_FILL.