I have a question about the opengl modal draw :

How to align text from a modal draw to the middle of the viewport and and keep it automatic between Tool Shelf and Property Shelf, when i changing them?

I want to avoid that the property shelf overlapp the modal draw on the right viewport side, when i change the scale of left toolshelf.

Maybe there is a similar question always done?

  • 1
    $\begingroup$ You draw in the window type region of the space you are drawing text on (eg the 3d view). The x, y, width and height attributes of the region take into account the tool / property bars. $\endgroup$
    – batFINGER
    May 2 '18 at 12:21
  • 1
    $\begingroup$ If the text is generated dynamically, major issue is calculating the position based on the width to get it centered (IMHO). Probably related: blender.stackexchange.com/q/57709/31447 $\endgroup$
    – brockmann
    May 2 '18 at 12:26

According to the API, Area.region collection holds all "regions of the screen area" as well as their dimensions. In case of the 3d Viewport: Header, Transform Panel and N-Panel.

The following code is based on this answer, extended with a simple calculation to get the correct position of the text in the 3d Viewport. Notice that you can also iterate through the collection and sum up the dimensions instead of doing that stepwise.

enter image description here

import bpy
import bgl
import blf

def draw_callback_px(self, context):


    # ...api_current/bpy.types.Area.html?highlight=bpy.types.area
    header_height = context.area.regions[0].height # 26px
    npanel_width = context.area.regions[1].width
    transorm_panel_width = context.area.regions[3].width

    width = context.area.width - npanel_width - transorm_panel_width
    height = context.area.height + header_height

    # draw text
    text = "Hello World"
    font_id = 0  # XXX, need to find out how best to get this.
    bgl.glColor4f(*(1.0, 1.0, 1.0, 1))
    blf.size(font_id, 70, 72)
    dim_x = blf.dimensions(font_id, text)[0]/2
    dim_y = blf.dimensions(font_id, text)[1]
    blf.position(font_id, width/2-dim_x, height/2-dim_y, 0)
    blf.draw(font_id, text)

    # restore opengl defaults
    bgl.glColor4f(0.0, 0.0, 0.0, 1.0)

class ModalDrawOperator(bpy.types.Operator):
    """Draw a line with the mouse"""
    bl_idname = "view3d.modal_operator"
    bl_label = "Simple Modal View3D Operator"

    def modal(self, context, event):

        if event.type in {'RIGHTMOUSE', 'ESC'}:
            bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
            return {'CANCELLED'}

        return {'RUNNING_MODAL'}

    def invoke(self, context, event):
        if context.area.type == 'VIEW_3D':
            # the arguments we pass the the callback
            args = (self, context)
            # Add the region OpenGL drawing callback
            # draw in view space with 'POST_VIEW' and 'PRE_VIEW'
            self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, args, 'WINDOW', 'POST_PIXEL')
            return {'RUNNING_MODAL'}
            self.report({'WARNING'}, "View3D not found, cannot run operator")
            return {'CANCELLED'}

def register():

def unregister():

if __name__ == "__main__":

To display the text as well as allow the user to interact with the UI, you can change the return statement of the modal function from {'RUNNING_MODAL'} to {'PASS_THROUGH'}:


def modal(self, context, event):

    if event.type in {'RIGHTMOUSE', 'ESC'}:
        bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
        return {'CANCELLED'}

    return {'PASS_THROUGH'}


enter image description here

Also see the API on Modal Execution: https://docs.blender.org/api/blender_python_api_current/bpy.types.Operator.html#modal-execution

  • $\begingroup$ Thank you! That's really detailed. Again briefly repeated: >> total window minus tpanel minus npanel results is real area. >> divided by 2 for the center point. >> minus lenght of the text divided also by 2 $\endgroup$
    – MKB
    May 3 '18 at 11:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.