# how add properties to operator modal draw?

UPDATE

Here another example in order to clarify this question, I did a video in order to resume the problem https://www.youtube.com/watch?v=yShhJOzkJBk:

here the addon working without the BGL CODE.... as you see the properties are working too:

but if I allow the BGL code many strange things happen:

• properties unavailable
• the mesh deforms uncontrollably
• in some cases blender crash

what I'm doing wrong?

here the full code of this test:

'''

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.    See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

END GPL LICENCE BLOCK
'''

bl_info = {
"name": "Test bgl + joinmeshr",
"author": "Diego Quevedo ( http://doshape.com/ )",
"version": (1, 0),
"blender": (2, 7 , 3),
"location": "View3D > EditMode > ToolShelf",
"description": "Testing bgl",
"warning": "",
"wiki_url": "",
"tracker_url": "",
"category": "Mesh"}

import bpy
import bmesh
import mathutils
import math
from bpy_extras import view3d_utils
import time
import sys
import bgl
import blf

def draw_callback_px(self, context):

oa = bpy.context.active_object
obj = bpy.context.object
me = obj.data
bm = bmesh.from_edit_mesh(me)

for area in bpy.context.screen.areas:
if area.type == 'VIEW_3D':
override = bpy.context.copy()
viewport = area.regions[4]
v_m = area.spaces[0].region_3d.view_matrix  #orientation matrix

vertices= [v for v in bm.verts if (v.select == True and v.hide == False)]

vn1 = vertices[0]

vn2 = bm.verts.new(vn1.co)

vn3 = bm.verts.new(vn1.co)

#vector conversion from view space to world space

vn1.select = False
vn2.select = True
vn3.select = False
bm.select_history.active
values = mathutils.Vector((1,0,0))*v_m

#the translation is done in global orientation without any constraints
bpy.ops.transform.translate(value=values)

#bpy.context.object.location += values   #another way to translate

vn1.select = False
vn2.select = False
vn3.select = True
bm.select_history.active
values = mathutils.Vector((0,1,0))*v_m

bpy.ops.transform.translate(value=values)
vn3.select=False
vn1.select = True
bm.select_history.active
vn2.select = True
vn3.select = True

font_id = 0  # XXX, need to find out how best to get this.

# draw some text
#blf.position(font_id, 0, 0, 0)
#blf.size(font_id, 20, 72)
#blf.draw(font_id, oa.name)

# 50% alpha, 2 pixel width line
bgl.glEnable(bgl.GL_BLEND)
bgl.glColor4f(1.0, 1.0, 1.0, 0.5)
bgl.glLineWidth(2)

bgl.glBegin(bgl.GL_LINE_STRIP)
bgl.glVertex3f(*vn1.co)
bgl.glVertex3f(*vn2.co)

bgl.glBegin(bgl.GL_LINE_STRIP)
bgl.glVertex3f(*vn1.co)
bgl.glVertex3f(*vn3.co)
#bgl.glVertex3f(*ob.matrix_world.translation)
#bgl.glVertex3f(*context.scene.cursor_location)
bgl.glEnd()

# restore opengl defaults
bgl.glLineWidth(1)
bgl.glDisable(bgl.GL_BLEND)
bgl.glColor4f(0.0, 0.0, 0.0, 1.0)

#SEND TO CUT
#calcularangulos1(v1, v3, v2,angle)

listabasuravertices0= [vn2,vn3]
bmesh.ops.delete(bm, geom= listabasuravertices0, context=1)
bmesh.update_edit_mesh(me, True)

################################################################################
######  testbgl##########################################
################################################################################

class testbglOperator(bpy.types.Operator):
"testbgl"
bl_idname = 'mesh.testbgl'
bl_label = 'testbgl'
bl_description  = "test bgl"
bl_options = {'REGISTER', 'UNDO'}

chboxjoin0 = bpy.props.BoolProperty(
name="Join",
default= True
)
chboxVert1 = bpy.props.BoolProperty(
name="Select",
default= True
)

def main(self, context, chboxjoin0, chboxVert1):

#almacena caras

obj = bpy.context.object
me = obj.data
bm = bmesh.from_edit_mesh(me)

v1, v2= [v for v in bm.verts if (v.select == True and v.hide == False)]

if chboxjoin0:
bpy.ops.mesh.vert_connect_path()

if chboxVert1:
v1.select = True
v2.select= True
else:
v1.select = False
v2.select= False

bmesh.update_edit_mesh(me, True)

@classmethod

def poll(self, context):
obj = context.active_object
return all([obj is not None, obj.type == 'MESH', obj.mode == 'EDIT'])
'''
def execute(self, context):

self.main(context, self.chboxjoin0, self.chboxVert1)

#bisectoroperator(self)
return {'FINISHED'}
'''
def modal(self, context, event):
context.area.tag_redraw()

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

return {'PASS_THROUGH'}

def invoke(self, context, event):
#self.main(context, self.chboxjoin0, self.chboxVert1)

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_VIEW')

self.mouse_path = []

self.main(context, self.chboxjoin0, self.chboxVert1)
return {'RUNNING_MODAL'}
else:
return {'CANCELLED'}

class TestbglOperatorPanel(bpy.types.Panel):
#bl_category = "Bisector"
bl_space_type = "VIEW_3D"
bl_region_type = "TOOLS"

#bl_context = "editmode"
bl_label = " Test bgl"
@classmethod
def poll(cls, context):
return (context.mode == 'EDIT_MESH')

def draw(self, context):
layout = self.layout

row = layout.row(align=True)
row.operator(testbglOperator.bl_idname) #testbgl

def register():
bpy.utils.register_module(__name__)

def unregister():
bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
register()


---------------------------

*I'm making some bgl test, but I have for example this problem: In this case I have the template operator_modal_draw and I want to add some int property in order to change the line width... something like: width = bpy.props.IntProperty(
name="line width",
default=10,
description="", min=2 ) I did a lot of test but I don't have any good result do you have some ideas?

• it might help to describe the goal of your experiment, as it stands the template for operator modal draw code won't let you interact with the UI anyway so you wouldn't be able to drag a slider if it was added. – zeffii May 3 '15 at 7:18
• @zeffii thanks for your comment, I update the post with more data.. thanks for any help – yhoyo May 3 '15 at 15:37
• i'm still not sure I understand what you are trying to achieve. Though I think it's not a great idea to be mixing bmesh mesh updates and bgl calls inside the one bgl callback (but I cannot prove with facts yet why I think that's a bad idea). – zeffii May 3 '15 at 16:36
• I encourage you to make a GitHub repository for the test, this will allow you to make branches. Master would have the code without bgl drawing and test branches would have various different approaches. The benefit is that you don't have to keep track of what code to comment / uncomment. The sooner you include branches in your development process the less hectic it will be. – zeffii May 5 '15 at 5:16
• can you please explain what you are trying to do in draw_callback_px, i can read the code, but you need to explain what you think it should be doing. Avoid mixing bmesh operations inside your bgl callback. if you want to define drawing characteristics for your bgl, then create a panel and use scene properties. As it stands I think the question is too broad. and the code far too long to be considered a condensed demo. – zeffii May 5 '15 at 6:18

To answer your questions, I think it makes more sense in the end to have a panel for the script. Sometimes you have to build up extra scaffolding for a script, even for testing. I don't think it is necessary to draw properties to the operator's own panel, you might even want to hide that from appearing anywhere on the UI.

This is a combination of two templates from the Text Editor templates menu.

To demo this you create a cube, and delete all edges so you have only vertices remaining. Run the code from text editor, then to start drawing you press the Simple modal draw..button which appears in the 3dview N panel at the bottom. If I understand the question (and it is entirely possible that I don't and there's some language barrier), You want to have access to the rest of 3d view UI while drawing, you want to adjust some settings for the bgl.

animated gif of demo

This short snippet lets you adjust the line thickness while the bgl still draws. Below the code I talk about some issues I have with your own code, (and ways to avoid crashing)

import bpy
import bgl
import blf

def draw_callback_px(self, context):

# 50% alpha, 2 pixel width line
bgl.glEnable(bgl.GL_BLEND)
bgl.glColor4f(0.0, 0.0, 0.0, 0.5)
bgl.glLineWidth(context.scene.BGL_DEMO_PROP_THICKNESS)

bgl.glBegin(bgl.GL_LINE_STRIP)
for co in self.mouse_path:
bgl.glVertex3f(*co)

bgl.glEnd()

# restore opengl defaults
bgl.glLineWidth(1)
bgl.glDisable(bgl.GL_BLEND)
bgl.glColor4f(0.0, 0.0, 0.0, 1.0)

class ModalDrawOperator(bpy.types.Operator):

bl_idname = "view3d.bgl_demo_modal_operator"
bl_label = "Simple Modal View3D Operator"

def modal(self, context, event):
context.area.tag_redraw()

if event.type in {'MIDDLEMOUSE'}:
return {'RUNNING_MODAL'}

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

return {'PASS_THROUGH'}

def invoke(self, context, event):
if context.area.type == 'VIEW_3D':
args = (self, context)

self._handle = draw_handler_add(draw_callback_px, args, 'WINDOW', 'POST_VIEW')

self.mouse_path = [v.co for v in context.active_object.data.vertices]

return {'RUNNING_MODAL'}
else:
return {'CANCELLED'}

class HelloWorldPanel(bpy.types.Panel):
"""Creates a Panel in the Object properties window"""
bl_label = "Hello World Panel"
bl_idname = "OBJECT_PT_hello"
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
# bl_context = "object"

def draw(self, context):
layout = self.layout
col = layout.column()
col.prop(context.scene, 'BGL_DEMO_PROP_THICKNESS', text='thickness')
col.operator("view3d.bgl_demo_modal_operator")

def register():
bpy.types.Scene.BGL_DEMO_PROP_THICKNESS = bpy.props.IntProperty(default=1, max=5)
bpy.utils.register_class(HelloWorldPanel)
bpy.utils.register_class(ModalDrawOperator)

def unregister():
bpy.utils.unregister_class(HelloWorldPanel)
bpy.utils.unregister_class(ModalDrawOperator)
del bpy.types.Scene.BGL_DEMO_PROP_THICKNESS

if __name__ == "__main__":
register()


Things to avoid.

• Don't mix bmesh and bpy.ops.mesh while working on the same mesh, that's a recipe for bad code and potential crashes.

if chboxjoin0:
# bpy.ops.mesh.vert_connect_path()
bm.edges.new([v1, v2])

• BGL is one of the few areas in blender that will cause crashes to desktop, you must deal with all errors/exceptions inside your bgl callback, and return the BGL to a safe default state if there are errors.

• don't mix geometry modifications inside your bgl callback
• separate bgl parts from bmesh/mesh operations
• perform mesh operations first, then draw the results.
• switching contexts inside bgl callback, probably not a good idea.
• start a lot simpler, maybe even with completely unrelated code just to get a better understanding of the interactions between various parts of your code.
• thanks for answer... why this don't work in 3D only in 2d?, how I should mix geometry modifications + bgl? still testing with your sample. – yhoyo May 6 '15 at 13:31
• This bgl drawing callback is 3d. see bgl.glVertex3f(*co) I just reused the mousepath variable to store the list of 3d vectors. Unfortunatelyi'm not aware of many examples of trivial bgl usage that I can point to, but perhaps this might be interesting: gist.github.com/zeffii/9451340 (index viewer uses bgl) – zeffii May 6 '15 at 13:50

Since clicking while trying to set a value on the UI will cause the operator to stop I suggest altering the property by catching an event like key press or mouse wheel, as an example :

# in modal()
elif event.type == 'WHEELUPMOUSE':
self.width += 1
elif event.type == 'WHEELDOWNMOUSE':
self.width -= 1

# in draw_callback_px()
bgl.glLineWidth(self.width)


Now scrolling the mouse wheel will increase/decrease the line width

you can also register a new panel where you can set the variables and launch the operator

• thanks for write, but this don't solve the question.... how add properties to operador modal draw? is possible?? – yhoyo May 2 '15 at 23:30
• sorry I don't know if it is possible – Chebhou May 2 '15 at 23:43
• I update the post with more data and other examples in order to clarify this problem. thanks for any help – yhoyo May 3 '15 at 15:38