Button

It’s a class.

Button is the most important complete UI that can be created. Complete , means all other UI types are created using Button only, either by inheritance or by creating it’s instance.

Therefore, TextField, IntField, CheckBox etc are all child of Button or have Button instance. Their Vector counterpart eg. VectorIntField has three Button instances.

Note

This page and Event and Callback are very important, read carefully with patience

Simplest button requires two non-optional parameter:

  • op:

    type: Boss_OT_base_ui

    It’s reference of the operator, inherited from Boss_OT_base_ui

  • rectData:

    type: RectData

    Rectangle of the panel.

1
2
3
4
5
6
7
from boss.ui_creator import UICreator,RectData #,Button

def ui_elements(op):
    # Button(op, RectData(10,10,100,50))
    # or
    UICreator.button(op,RectData(10,10,100,50))

Default behaviour:

  • By default button is draggable.

  • By default button can’t be dragged outside the view region.

  • By default button adds callback to change color onEnter and onExit.

Above code does nothing when clicked, a more usable Button can be created using following code:

from boss.ui_creator import UICreator, Boss_OT_base_ui

def createCube():
    import bpy
    bpy.ops.mesh.primitive_cube_add(size=2)

def ui_elements(op:Boss_OT_base_ui):
    UICreator.button(op, (10, 10, 200, 100), 'Cube', createCube)

Above code Creates a Button near bottom left, when clicked, a Cube is created.

from boss.ui_creator import UICreator

def ui_elements(op):
    UICreator.button(op, (10, 60, 100, 50), 'Cube',
                     lambda : exec('\n'.join(('import bpy',"bpy.ops.mesh.primitive_cube_add(size=2)"))))

Above code does the same but uses lambda function. This way you can create several buttons without explicitly defining function.

Here is how a button will look with all the supported parameters

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
from boss.ui_creator import UICreator, Boss_OT_base_ui, ButtonData, RectData


def onClicked():
    print('Button is Clicked')

def dragging(some_param):
    print(some_param)


def onWheel(caller, addby):
    caller.param += addby
    print('param is now', caller.param)


def ui_elements(op: Boss_OT_base_ui):
    UICreator.button(
        op=op,
        rectData=RectData(10, 110, 200, 100),
        text='ButtonText',
        buttonData=ButtonData(
            onClick=onClicked,
            onMouseEnter=lambda: print('mouse entered'),
            onMouseExit=lambda: print('mouse exited'),
            onWheelUp=(onWheel, 1),
            onWheelDown=(onWheel, -1),
            onDragBegin=(dragging, 'dragging is started'),
            onDrag=(dragging, "it's being dragged"),
            onDragEnd=(dragging, 'dragging is ended')
        ),
        ttt='tool tip text',
        tti='',
        canDrag=True,
        parent=None,
        rectIsLocal=False,
        param=100
    )
  • You can think of Button as, Button = It’s Shape and Size + Interectivity, where Shape and Size is defined by the parameters that are part of creating a Panel and Interactivity is provided using ButtonData object.

  • So, Button inherits from Panel, and ButtonData is only extra parameter that is required. You can compare Panel Parameters with above code and see the ButtonData is the extra parameter.

ButtonData

It’s a class.

This class object is used to pass callback function for button events.

This is part of the above code, that first creates ButtonData object, then uses this buttonData to create Button.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
from boss.ui_creator import UICreator, Boss_OT_base_ui, ButtonData, RectData


def createCube():
    import bpy
    bpy.ops.mesh.primitive_cube_add(size=2)


def onClicked():
    print('Button is Clicked')


def dragging(some_param):
    print(some_param)


def onWheel(caller, addby):
    caller.param += addby
    print('param is now', caller.param)


def ui_elements(op: Boss_OT_base_ui):
    buttonData = ButtonData(
        onClick=onClicked,
        onMouseEnter=lambda: print('mouse entered'),
        onMouseExit=lambda: print('mouse exited'),
        onWheelUp=(onWheel, 1),
        onWheelDown=(onWheel, -1),
        onDragBegin=(dragging, 'dragging is started'),
        onDrag=(dragging, "it's being dragged"),
        onDragEnd=(dragging, 'dragging is ended')
    )
    UICreator.button(
        op=op,
        rectData=RectData(10, 110, 200, 100),
        text='ButtonText 1',
        buttonData=buttonData,
        ttt='tool tip text',
        param=100
    )
    UICreator.button(
        op=op,
        rectData=RectData(10, 210, 200, 100),
        text='ButtonText 2',
        buttonData=buttonData,
        ttt='tool tip text',
        param=100
    )

From the above code you can see, Several buttons can be created using same buttonData.

Notes:

  • You can create buttons in a loop with the same buttonData, in different locations (using different RectData list).

  • Button doesn’t store reference to buttonData.

  • Obviously, You don’t need all the callbacks in one Button, this example is just for demonstration, add callback only for what you need.

Note

You must have read event and callbacks by now.

Button Events

  • onClick : called when button is clicked

  • onHover : onHover isn’t implemented.

  • onMouseEnter : when mouse entered the rect of button

  • onMouseExit : when mouse exited the rect of button

  • onWheelUp : mouse wheel (middle button) rolled up

  • onWheelDown : mouse wheel (middle button) rolled down.

  • onDragBegin : when mouse (LMB) is pressed.

  • onDrag : when mouse (LMB) move moves, being pressed.

  • onDragEnd : when mouse (LMB) if lifted

Following code shows all the add_eventName method of Button object.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from boss.ui_creator import UICreator, Boss_OT_base_ui, RectData


def onClicked():
    print('Button is Clicked')


def dragging(some_param):
    print(some_param)


def onWheel(caller, addby):
    caller.param += addby
    print('param is now', caller.param)


def ui_elements(op: Boss_OT_base_ui):
    button = UICreator.button(
        op=op,
        rectData=RectData(10, 110, 200, 100),
        text='ButtonText',
        buttonData=None,
        ttt='tool tip text',
        param=100
    )

    button.add_onClick(onClicked)
    button.add_onMouseEnter(lambda: print('mouse entered'))
    button.add_onMouseExit(lambda: print('mouse exited'))
    button.add_onWheelUp((onWheel, 1))
    button.add_onWheelDown((onWheel, -1))
    button.add_onDragBegin((dragging, 'dragging is started'))
    button.add_onDrag((dragging, "it's being dragged"))
    button.add_onDragEnd((dragging, 'dragging is ended'))

Notes:

  1. Every button added needs to be checked whether mouse cursor is within its rect. It happens whenever mouse moves. More buttons you add, more time it would take. Generally, 10 to 20 buttons, are required for creating any simple functionality.But, create 100,200 buttons is still doable. In future updates, as project will grow, there will be some way to accelerate this using trees, hashing, area partitioning etc.

  2. Since Panel isn’t interactive, it has very few uses. During development, a Panel was enough to be draggable and change it’s color. To keep all the interactivity and callbacks in one class, all code for callback was removed from Panel to Button. Now a Button is required to change Panel properties of canDrag and color.

  3. What is Click? , If mouse is down and up in the same co-ordinate position, the up event becomes the click. If mouse moved, even by 1 px, when held down, its NOT a click. (its a Drag). Some times click doesn’t work, this could be the reason.