# How to add modal modifiers?

**URL:** <https://blenderartists.org/t/how-to-add-modal-modifiers/1564461>\
**Category:** Python Support\
**Tags:** scripting\
**Created:** [December 25, 2024, 4:59pm UTC](https://blenderartists.org/t/how-to-add-modal-modifiers/1564461 "2024-12-25T16:59:54Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![obsurveyor](https://blenderartists.org/user_avatar/blenderartists.org/obsurveyor/32/1476547_2.png) [@obsurveyor](https://blenderartists.org/u/obsurveyor)\
**Post date:** [December 25, 2024, 4:59pm UTC](https://blenderartists.org/t/how-to-add-modal-modifiers/1564461/1 "2024-12-25T16:59:54Z")

</div>

![blender_modal_modifier](https://blenderartists.org/uploads/default/original/4X/7/2/e/72e3a2550bafbb842bdf729bfeedfa12cee6449d.png)  
(I’m currently running Shrink/Fatten in this screenshot screenshot, at the bottom: Confirm, Cancel, Snap Invert, Snap Toggle, Precision Mode)

I don’t know what these are called. Modifiers? Is it possible to add them to my own addon’s modal operators’ UI so my modifier keys appear at the bottom of the window? Any examples?

edit: for clarity

---

<div class="post-metadata">

**Author:** ![Andrej](https://blenderartists.org/user_avatar/blenderartists.org/andrej/32/914017_2.png) [@Andrej](https://blenderartists.org/u/Andrej)\
**Post date:** [December 25, 2024, 6:16pm UTC](https://blenderartists.org/t/how-to-add-modal-modifiers/1564461/2 "2024-12-25T18:16:14Z")

</div>

> <https://stackoverflow.com/questions/45909657/using-a-key-modifier-with-blender-modal>

---

<div class="post-metadata">

**Author:** ![obsurveyor](https://blenderartists.org/user_avatar/blenderartists.org/obsurveyor/32/1476547_2.png) [@obsurveyor](https://blenderartists.org/u/obsurveyor)\
**Post date:** [December 25, 2024, 6:23pm UTC](https://blenderartists.org/t/how-to-add-modal-modifiers/1564461/3 "2024-12-25T18:23:04Z")

</div>

Thanks but I know how to add the key detection. I don’t know how to get it to appear in the UI at the bottom of the window when the modal is running.

---

<div class="post-metadata">

**Author:** ![Andrej](https://blenderartists.org/user_avatar/blenderartists.org/andrej/32/914017_2.png) [@Andrej](https://blenderartists.org/u/Andrej)\
**Post date:** [December 25, 2024, 7:21pm UTC](https://blenderartists.org/t/how-to-add-modal-modifiers/1564461/4 "2024-12-25T19:21:40Z")

</div>

There’s [https://docs.blender.org/api/current/bpy.types.WorkSpace.html#bpy.types.WorkSpace.status\_text\_set\_internal](https://docs.blender.org/api/current/bpy.types.WorkSpace.html#bpy.types.WorkSpace.status_text_set_internal) but not sure about an example.

---

<div class="post-metadata">

**Author:** ![obsurveyor](https://blenderartists.org/user_avatar/blenderartists.org/obsurveyor/32/1476547_2.png) [@obsurveyor](https://blenderartists.org/u/obsurveyor)\
**Post date:** [December 26, 2024, 1:18am UTC](https://blenderartists.org/t/how-to-add-modal-modifiers/1564461/5 "2024-12-26T01:18:47Z")

</div>

Thanks, that is sounds like it might be what I’m looking for. I’ll look through other addons and see if I can find anything that uses it.

---

<div class="post-metadata">

**Author:** ![Andrej](https://blenderartists.org/user_avatar/blenderartists.org/andrej/32/914017_2.png) [@Andrej](https://blenderartists.org/u/Andrej)\
**Post date:** [December 26, 2024, 7:05am UTC](https://blenderartists.org/t/how-to-add-modal-modifiers/1564461/6 "2024-12-26T07:05:25Z")

</div>

Got curious how would it work with the icons and turned out `status_text_set` is just a Python defined method that works with `STATUSBAR_HT_header.draw`.

> **[blender/bpy\_types.py at 7a1e95ea91b1bda54c836d0572a1e8a39ac21316](https://projects.blender.org/blender/blender/src/commit/7a1e95ea91b1bda54c836d0572a1e8a39ac21316/scripts/modules/bpy_types.py#L309-L324:)**
>
> blender - The official Blender project repository.

```python
class WorkSpace(_types.ID):
    __slots__ = ()

    def status_text_set(self, text):
        """
        Set the status text or None to clear,
        When text is a function, this will be called with the (header, context) arguments.
        """
        from bl_ui.space_statusbar import STATUSBAR_HT_header
        draw_fn = getattr(STATUSBAR_HT_header, "_draw_orig", None)
        if draw_fn is None:
            draw_fn = STATUSBAR_HT_header._draw_orig = STATUSBAR_HT_header.draw

        if not (text is None or isinstance(text, str)):
            draw_fn = text
            text = None

        self.status_text_set_internal(text)
        STATUSBAR_HT_header.draw = draw_fn

```

Basically, it allows you to set your own `draw()` method for the `STATUSBAR_HT_header` and create a more fancy status with icons:

```python
bpy.context.workspace.status_text_set(lambda self, context: self.layout.label(text="hi", icon="KEY_TAB"))

```

![image](https://blenderartists.org/uploads/default/original/4X/8/6/2/8620f6450f55f6e4b30979b478b3a62ddfb97cc3.png)

---

<div class="post-metadata">

**Author:** ![obsurveyor](https://blenderartists.org/user_avatar/blenderartists.org/obsurveyor/32/1476547_2.png) [@obsurveyor](https://blenderartists.org/u/obsurveyor)\
**Post date:** [December 26, 2024, 11:39am UTC](https://blenderartists.org/t/how-to-add-modal-modifiers/1564461/7 "2024-12-26T11:39:58Z")

</div>

I did find this code in the `modules/bpy_types.py` but what is `C` in this example?

---

<div class="post-metadata">

**Author:** ![Secrop](https://blenderartists.org/user_avatar/blenderartists.org/secrop/32/20093_2.png) [@Secrop](https://blenderartists.org/u/Secrop)\
**Post date:** [December 26, 2024, 11:47am UTC](https://blenderartists.org/t/how-to-add-modal-modifiers/1564461/8 "2024-12-26T11:47:00Z")

</div>

`C` is the console shortcut for `bpy.context`. (it shows when you open a Python Console Editor, in last line)

```auto
PYTHON INTERACTIVE CONSOLE 3.11.9 (main, Oct 15 2024, 19:17:05) [MSC v.1929 64 bit (AMD64)]

Builtin Modules: bpy, bpy.data, bpy.ops, bpy.props, bpy.types, bpy.context, bpy.utils, bgl, gpu, blf, mathutils
Convenience Imports: from mathutils import *; from math import *
Convenience Variables: C = bpy.context, D = bpy.data

```

---

<div class="post-metadata">

**Author:** ![obsurveyor](https://blenderartists.org/user_avatar/blenderartists.org/obsurveyor/32/1476547_2.png) [@obsurveyor](https://blenderartists.org/u/obsurveyor)\
**Post date:** [December 26, 2024, 12:52pm UTC](https://blenderartists.org/t/how-to-add-modal-modifiers/1564461/9 "2024-12-26T12:52:59Z")

</div>

Thanks, I guess I’ve just always ignored that text in the Python console and typed `bpy.context` because I totally forgot it was even there.

Thanks @Andrej too!

I wonder if there’s a way to reset that bar, because after using it, it doesn’t go back when the modal exits, leaving edit mode or even using another modal that uses it internally. Setting `context` to `None` just makes the bar blank forever.

Ahh `bpy.context.workspace.status_text_set(None)` does it.

---

<div class="post-metadata">

**Author:** ![Secrop](https://blenderartists.org/user_avatar/blenderartists.org/secrop/32/20093_2.png) [@Secrop](https://blenderartists.org/u/Secrop)\
**Post date:** [December 26, 2024, 1:08pm UTC](https://blenderartists.org/t/how-to-add-modal-modifiers/1564461/10 "2024-12-26T13:08:13Z")

</div>

The `text` parameter is the one which is supposed to be `None`… (not the context)  
(the example from Andrej isn’t probably the best to clarify the `status_text_set` function…)

You could also check the `startup\bl_operators\wm.py` to see how that function can be used.  
(or the function itself, in `modules\bpy_types.py`)

```auto
>>> help(bpy.context.workspace.status_text_set)
Help on method status_text_set in module bpy_types:

status_text_set(text) method of bpy_types.WorkSpace instance
    Set the status text or None to clear,
    When text is a function, this will be called with the (header, context) arguments.

```

---

<div class="post-metadata">

**Author:** ![obsurveyor](https://blenderartists.org/user_avatar/blenderartists.org/obsurveyor/32/1476547_2.png) [@obsurveyor](https://blenderartists.org/u/obsurveyor)\
**Post date:** [December 26, 2024, 1:36pm UTC](https://blenderartists.org/t/how-to-add-modal-modifiers/1564461/11 "2024-12-26T13:36:27Z")

</div>

I guess the last piece to this puzzle would be to invert the icon when my modifier is active if you have any ideas.

---

<div class="post-metadata">

**Author:** ![Secrop](https://blenderartists.org/user_avatar/blenderartists.org/secrop/32/20093_2.png) [@Secrop](https://blenderartists.org/u/Secrop)\
**Post date:** [December 26, 2024, 1:52pm UTC](https://blenderartists.org/t/how-to-add-modal-modifiers/1564461/12 "2024-12-26T13:52:32Z")

</div>

You probably have some internal ‘state’ in your modal operator, right?

If that’s the case, you could use pass a function that generates the correct status\_text (based on the internal state) to the `status_text_set`.

---

<div class="post-metadata">

**Author:** ![obsurveyor](https://blenderartists.org/user_avatar/blenderartists.org/obsurveyor/32/1476547_2.png) [@obsurveyor](https://blenderartists.org/u/obsurveyor)\
**Post date:** [December 26, 2024, 1:58pm UTC](https://blenderartists.org/t/how-to-add-modal-modifiers/1564461/13 "2024-12-26T13:58:28Z")

</div>

The issue is I can’t get it to look like Blender with the icon inverted next to the text:  
 ![blender_modifier_on](https://blenderartists.org/uploads/default/original/4X/d/b/8/db87320df1f5f25f95561b85d03acfa7b61e2577.png)

Width and Clamp are active in the Bevel operator here.

Closest I’ve been able to get with mine is using a `prop` but it looks ugly:  
 ![blender_modifier_mine](https://blenderartists.org/uploads/default/original/4X/c/2/e/c2eff357e7c66ee5ad3ddf9d2a35e5d2a8f99dab.png)

(`icon_only` looks the same just without the text)

---

<div class="post-metadata">

**Author:** ![Secrop](https://blenderartists.org/user_avatar/blenderartists.org/secrop/32/20093_2.png) [@Secrop](https://blenderartists.org/u/Secrop)\
**Post date:** [December 26, 2024, 2:24pm UTC](https://blenderartists.org/t/how-to-add-modal-modifiers/1564461/14 "2024-12-26T14:24:16Z")

</div>

Ohh… Now I understand your problem.

I don’t think the `inverted` parameter is exposed to the Python API…  
The C function that uses it is `ed_workspace_status_item` (blender\editors\screen\area.cc), and it’s an attribute of `bke::WorkSpaceStatusItem`, which I believe is not included in the API.

I would need to dig a bit further, but probably some changes to the source are required.

---

<div class="post-metadata">

**Author:** ![obsurveyor](https://blenderartists.org/user_avatar/blenderartists.org/obsurveyor/32/1476547_2.png) [@obsurveyor](https://blenderartists.org/u/obsurveyor)\
**Post date:** [December 26, 2024, 2:44pm UTC](https://blenderartists.org/t/how-to-add-modal-modifiers/1564461/15 "2024-12-26T14:44:21Z")

</div>

Ahh! Well, maybe we’ll see that in the future then. I’m 99% there thanks to your clarifications. I’ll think I’ll just change the text for now.

---

<div class="post-metadata">

**Author:** ![Andrej](https://blenderartists.org/user_avatar/blenderartists.org/andrej/32/914017_2.png) [@Andrej](https://blenderartists.org/u/Andrej)\
**Post date:** [December 26, 2024, 4:44pm UTC](https://blenderartists.org/t/how-to-add-modal-modifiers/1564461/16 "2024-12-26T16:44:03Z")

</div>

There are two ways to provide icon to UI - `icon` and `icon_value`. Perhaps there is a way to offset `icon_value` of the button icon to “invert” it.

You can use the patch below and see the system console for actual icon values used for each element - so you’ll be able to see what value is used for normal and inverted icons, maybe it will give some clues.

```python
from bl_ui.space_statusbar import STATUSBAR_HT_header

def clever_draw(self, context):
    self.layout.label(text="test")
    STATUSBAR_HT_header._draw_orig(self, context)
    print(self.layout.introspect())

```

---

<div class="post-metadata">

**Author:** ![obsurveyor](https://blenderartists.org/user_avatar/blenderartists.org/obsurveyor/32/1476547_2.png) [@obsurveyor](https://blenderartists.org/u/obsurveyor)\
**Post date:** [December 26, 2024, 5:14pm UTC](https://blenderartists.org/t/how-to-add-modal-modifiers/1564461/17 "2024-12-26T17:14:32Z")

</div>

I did look into `icon_value` but couldn’t figure out what it was used for. The docs for it are useless too.

I don’t think I have anywhere to plug in your introspection code because there aren’t any included Python operators that use `status_text_set`. I can’t run this in my operator because then it’s out of context when running a different operator so the introspection just errors.

edit: Actually, I figured out how to plug it in without reference to my class but the output doesn’t appear to change when Clamp is turned on or off in the Bevel operator. It doesn’t show icon information either.

Console output:

```auto
[{'type': 'LAYOUT_ROOT', 'items': [{'type': 10240, 'draw_string': 'test', 'tip': ''}, {'type': 'LAYOUT_ROW', 'items': [{'type': 10240, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': 'Confirm', 'tip': ''}, {'type': 27648, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': '', 'tip': ''}, {'type': 27648, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': 'Cancel', 'tip': ''}, {'type': 27648, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': 'Width Type', 'tip': ''}, {'type': 27648, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': 'Width', 'tip': ''}, {'type': 27648, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': 'Segments', 'tip': ''}, {'type': 27648, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': 'Profile', 'tip': ''}, {'type': 27648, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': 'Clamp', 'tip': ''}, {'type': 27648, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': 'Harden', 'tip': ''}, {'type': 27648, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': 'Seam', 'tip': ''}, {'type': 27648, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': 'Sharp', 'tip': ''}, {'type': 27648, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': 'Affect (Edges) ', 'tip': ''}, {'type': 27648, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': 'Outer (Sharp) ', 'tip': ''}, {'type': 27648, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': 'Inner (Sharp) ', 'tip': ''}, {'type': 27648, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': 'Profile Type (Superellipse) ', 'tip': ''}, {'type': 27648, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': 'Intersection (Grid Fill) ', 'tip': ''}, {'type': 27648, 'draw_string': '', 'tip': ''}]}, {'type': 28672, 'draw_string': '', 'tip': ''}, {'type': 28672, 'draw_string': '', 'tip': ''}, {'type': 'LAYOUT_ROW', 'items': []}, {'type': 'LAYOUT_ROW', 'items': [{'type': 10240, 'draw_string': 'Cube | Verts:4/42 | Edges:4/63 | Faces:1/31 | Tris:64 | Objects:1/3 | Memory: 27.8 MiB | VRAM: 5.1/6.0 GiB', 'tip': ''}, {'type': 27648, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': '|', 'tip': ''}, {'type': 27648, 'draw_string': '', 'tip': ''}, {'type': 10240, 'draw_string': '4.3.2', 'tip': ''}]}]}]

```

---

<div class="post-metadata">

**Author:** ![Andrej](https://blenderartists.org/user_avatar/blenderartists.org/andrej/32/914017_2.png) [@Andrej](https://blenderartists.org/u/Andrej)\
**Post date:** [December 26, 2024, 6:56pm UTC](https://blenderartists.org/t/how-to-add-modal-modifiers/1564461/18 "2024-12-26T18:56:08Z")

</div>

Oh, sorry, for some reason I assumed `icon_value` was part of introspection output.

There is a way to get `icon_value` for known `icon` as described in here [https://projects.blender.org/blender/blender/issues/97909#issue-14039](https://projects.blender.org/blender/blender/issues/97909#issue-14039) but not sure how to get it for the inverted icon to compare.

---

<div class="post-metadata">

**Author:** ![obsurveyor](https://blenderartists.org/user_avatar/blenderartists.org/obsurveyor/32/1476547_2.png) [@obsurveyor](https://blenderartists.org/u/obsurveyor)\
**Post date:** [December 26, 2024, 7:21pm UTC](https://blenderartists.org/t/how-to-add-modal-modifiers/1564461/19 "2024-12-26T19:21:27Z")

</div>

Well according to that link it should be -1, 0 or 1 but none of them invert the icon. In my case, I’m using `EVENT_C` which has no “next” icon according to the Icon Viewer addon. It is interesting that I don’t get like D or B though either.

After reading the responses to that bug report it seems like it’s kind of a rabbit hole and no one wants to make a decision on the “right” way to handle icons.

---

<div class="post-metadata">

**Author:** ![obsurveyor](https://blenderartists.org/user_avatar/blenderartists.org/obsurveyor/32/1476547_2.png) [@obsurveyor](https://blenderartists.org/u/obsurveyor)\
**Post date:** [December 26, 2024, 7:43pm UTC](https://blenderartists.org/t/how-to-add-modal-modifiers/1564461/20 "2024-12-26T19:43:17Z")

</div>

Leveraging(abusing?) the `emboss` and `invert_checkbox` parameters, I’ve got:

False:  
 ![my_mod_true](https://blenderartists.org/uploads/default/original/4X/4/0/0/4006c8361fd5a6ce43223b3d611d5e5e2bfcc32c.png)

True:  
 ![my_mod_false](https://blenderartists.org/uploads/default/original/4X/f/0/9/f0981aec308971ac2a1c4ce75aa76ebed5d8e4d4.png)

I don’t like the poor contrast but it is probably the best I can get until they expose the `inverted` parameter to Python like Secrop mentioned.

[Next page](https://blenderartists.org/t/how-to-add-modal-modifiers/1564461.md?page=2)
