ui menus and custom data...?

Hi I am trying to create a menu that will display a list.
I am really confused. I found a way to create buttons but I can’t figure out how to create a menu.

Can it be done. Can I create a drop down menu and the select witch one of the items in my list I wand to choose?

Thanks.

I’m kinda looking into this myself right now. I’m trying to enable the user to change default settings before a script is run and present data in a sensible way. Most useful to me right now is the UILayout type. Documentation (such as it is) can be found at http://www.blender.org/documentation/blender_python_api_2_54_0/bpy.types.UILayout.html

There are definitions of the constructor for menus, enums etc. I’m not quite sure how they are implemented or what data they can display just yet though. Hope you find what you’re looking for at the above link or elsewhere.

I think only object properties and operator properties are displayable. I would like confirmation of this. Based on this assumption, however, I am thinking of implementing a dummy operator that doesn’t actually do anything, but will serve as a place to store properties that it will use to call other functioning operators.

The answer of what you are looking for is YES…

For more info (2.49) look here

Regards,

Thanks for the response… but I still can’t figure it out.

Can someone please create a very simple example of a custom menu?

I am using blender 2.54

Im still working with Blender 2.4x so here’s my classic example for an interface in Blender 2.4x:

from Blender import *
from Blender.BGL import *

normal_info = 0
err_not_critical = 1
err_critical = 2
a_nice_message = 3
info_code = normal_info
threshold = 0.00001

msg = "Here is the Info bar..."
stNewRow = "
"
xLeft = 10
yUpperButtons = 490
wMax = 640
RowHeight = 15
RowDistance = 3
yRow = RowHeight + RowDistance
yLowerButtons = 35
yButton = 18
yBigButton = 25
wButton = 60
wb14 = int(1.4*wButton)

flOnlyOnce = True

menu_item = 1
num = 10
num_2 = 20
num_2_min = num
num_2_max = 5*num

#############################################################
# Graphics                                                                                                    #
#############################################################

def makeForm(st):
    global menu_item
    global num
    global num_2
    global num_2_min
    global num_2_max
    global value
    global mode

    y = yUpperButtons-RowHeight

    BGL.glClearColor(0.5, 0.5, 0.5, 1)
    BGL.glColor3f(0.8,0.6,0.6)  # Light red
    y = 3*yRow
    BGL.glRectf(4,yLowerButtons-2*yRow,800,y)
    BGL.glColor3f(0.6,0.8,0.6)  # Light green
    y = 21*yRow
    BGL.glRectf(4,yLowerButtons+4,800,y)
    BGL.glColor3f(0.8,0.6,0.6)  # Light red
    BGL.glRectf(4,y,800,y+5*yRow)
    x = xLeft
    y = yLowerButtons-yBigButton-2
    Draw.Button("Redraw",4,x,y,2*wButton,yBigButton)
    x = x+2*wButton
    Draw.Button("Exit",1,x,y,wMax,yBigButton)

    x = xLeft
    y = yLowerButtons+2*yRow
    # Double conversion cause after the first cycle    num results 
    num_val = int(str(num))    # in the Num value
    num = Draw.Number("Num_value:",2,x,y,2*wb14,yButton,num_val,0,100,"A test numeric control")
    
    x = x+5*wb14
    num_val_2 = int(str(num_2))    # in the Num 2 value
    num_2 = Draw.Number("Num_value_2:",3,x,y,2*wb14,yButton,num_val_2,num_2_min,num_2_max,"A test numeric control 2")

    y = yLowerButtons+6*yRow
    name = "The Title %t|First Entry %x1|Second Entry %x2|Third Entry %x3"
    # Double conversion cause after the first cycle    menu_item results 
    menu_val = int(str(menu_item))    # in a MenuItem value
    menu_item = Draw.Menu(name,5,x,y,2*wb14,yButton,menu_val,"A test menu")

    x = xLeft
    y = yUpperButtons+6
    BGL.glColor3f(1,1,0)
    BGL.glRasterPos2d(x,y)
    Draw.Text("Blender Interface test, ver. 0.1.0")
    BGL.glColor3f(0,0,1)
    y = y-yRow
    BGL.glRasterPos2d(x,y)
    Draw.Text("by Emil Lozanov <a.k.a. Abidos> - 2009")
    
    Info(st,info_code)
    
#######################################

def Info(st,info_code=normal_info):
    y = yUpperButtons+RowHeight+5
    Info_y(st,y,info_code)
    
def Info_y(st,y,info_code):
    if (info_code == normal_info):
        BGL.glColor3f(0,0,0.6)  # Dark blue
    elif (info_code == err_not_critical):
        BGL.glColor3f(0.8,0.6,0.6)  # Light red
    elif (info_code == err_critical):
        BGL.glColor3f(0.9,0,0)  # Bright red
    elif (info_code == a_nice_message):
        BGL.glColor3f(0,0.6,0)  # Dark green
    else:
        BGL.glColor3f(0,0,0)  # Black
    BGL.glRectf(xLeft,y,wMax,y+RowHeight)
    BGL.glColor3f(1,1,1)
    BGL.glRasterPos2d(xLeft+2,y+3)
    Draw.Text(st)

##############################################################

def draw():
    global msg
    global flOnlyOnce

    t = sys.time()
    st = "t = "+str(t)+"     "+msg
    
    makeForm(st)
    
    if flOnlyOnce:
        flOnlyOnce = False
        print
        print
        print "##############################################"
        print "#                                            #"
        print "#    * * *  Blender Interface test  * * *    #"
        print "#                                            #"
        print "#   Written by Emil Lozanov, a.k.a. Abidos   #"
        print "#                                            #"
        print "#         version 0.1.0 - 02.09.2009         #"
        print "#                                            #"
        print "##############################################"
        print
        ##### "        * * *   Done only once   * * *        "
        print
        print "==>>> Processing time = %.0f milliseconds" % (1000*(sys.time()-t))
        print
        print "========================================================================="
        print
        
#############################################################
#######         Event, bevent procs                 #####################
#############################################################

def event(evt,val): 
    global msg
    global value
    global mode

    if not val:
        return
    
    if (evt == Draw.QKEY) or (evt == Draw.ESCKEY):
        Draw.Exit()
        Redraw(Window.Types.SCRIPT)

#######################################

def bevent(evt):
    global msg
    global info_code
    global num
    global num_2
    global num_2_min
    global num_2_max
    
    info_code = normal_info
    if     (evt==1):
        Draw.Exit()
    elif (evt==2):  # Test NUM value ======================================
        st = "From bevent --> num_value = "+str(num)
        msg = st
        print st
        print
        num_2_min = int(str(num))
        num_2_max = 5*int(str(num))
        if num_2 < num_2_min:
            num_2 = num_2_min
        if num_2 > num_2_max:
            num_2 = num_2_max
    elif (evt==3):  # Test NUM value 2 ======================================
        st = "From bevent --> num_value 2 = "+str(num_2)
        msg = st
        print st
        print
    elif (evt==4):  # Test REDRAW feature ======================================
        st = "From bevent --> Redraw()"
        msg = st
        print st
        print
        info_code = a_nice_message
    elif (evt==5):  # Test MENU value ======================================
        st = "From bevent --> menu_item = "+str(menu_item)
        msg = st
        print st
        print
    elif (evt<=98):  # Not active yet.....
        st = "From bevent --> Not active yet..."
        msg = st
    elif (evt==99):  # Other ======================================
        st = "From bevent --> Other......"
        msg = st
        print st
        print
    elif (evt>99):  # Out of range.....
        st = "From bevent --> Out of range..."
        msg = st
        Draw.Exit()
    Redraw()

##############################################################

Draw.Register(draw, event, bevent)

Some constants may be not used in this example but it is takes from a bigger inteface so pls dont pay much attention on this. Anyway the above shows you creation and use of a menu plus 2 integer boxes that dependable - the second one can use values ONLY in the range of the value of the first one to 5 times this value. All actions are appropriately reported at a special InfoBar plus at the console. InfoBar change color is demonstrated by clicking the Redraw button… Actions (such as initializations) that are to me done only at the beginning are put in the the if flOnlyOnce: section in draw() proc. The event() and bevent() procs are expandable… Currently, bevent() proc effectively responds to button events from 1 to 5 and “supports” such events till 99… You may wish to customize it further - feel free to do so! :wink:

Referring to this thread, I’d call the menus “drop-ups” rather than “drop-downs”, unless you find a way to make them really drop-down (which I would be interested to know HOW-TO)… :cool:

Regards,

Thanks Adidos for your help.
I never writed a ui in blender 2.49 and blender 2.5 it’s to different.

I found one page that talks about custom properties http://wiki.blender.org/index.php/Doc:2.5/Manual/Extensions/Python/Properties
But I think it needs to get updated for 2.54

I created a simple example of menu but I don’t really know if it’s the right way to do it. Plus I have no idea how to get the users choice.


import bpy
from bpy.props import *

menu_item = "Measurement output type %t|Millimeters %x1|Centimeters %x2|Meters  %x3|Kilometers %x4|Inches %x5|Feet %x6|Yards %x7|Miles %x8|Blender Units  %x9"

bpy.types.Object.foo = EnumProperty(items = [] , name = menu_item)

class MyPanel(bpy.types.Panel):
    bl_label = "MyPanel"
    bl_idname = "myPanelID"
    bl_space_type = "PROPERTIES"
    bl_region_type = "WINDOW"
    bl_context = "object"
    
    def draw(self , context):
        layout = self.layout
        
        row = layout.row()
        row.prop(context.active_object , "foo")

The same way you can create check boxes (BoolProperty) , Sliders (IntProperty) and more.
Check the page about python api for 2.5 http://www.blender.org/documentation/250PythonDoc/

Also I cannot find out what I have to add to the items parameters of the EnumProperty…

Edit: I forgotten to tell that you will find the “MyMenu” to the PROPERTIES window and Object Panel.

Thanks.

OK I have done it. (Blender 2.54)


import bpy
from bpy.props import *

bpy.types.Object.foo = "bar"

bpy.types.Object.foo = EnumProperty(items = [("1" , "2" , "3") , ("return" , "name" , "description")] , name = "my_menu")

class MyPanel(bpy.types.Panel):
    bl_label = "MyPanel"
    bl_idname = "myPanelID"
    bl_space_type = "PROPERTIES"
    bl_region_type = "WINDOW"
    bl_context = "object"
    
    def draw(self , context):
        layout = self.layout
        
        row = layout.row()
        row.prop_menu_enum(context.active_object , "foo")
        print(context.active_object.foo)


Now this is a complete menu. Check it out.

About the param items in the function EnumProperty :
items (sequence of string triplets) – The items that make up this enumerator”
my example is [ [(“1” , “2” , “3”) , (“return” , “name” , “description”)] what is this…
We will get two menu items the first will be named “2” and the second “name”
From the triplet the first value is the String that we will get if the item is the selected item in the menu.
The second value is the name of the item in the menu.
The third value is the description.

I hope that I helped people that are confused like me. It took me to much time to figure out how it works. I just wanted to start a script for 2.5. Hope the api will not change to much till the stable 2.5 but then we will have and better documentation.

Thanks.

Well, Im still with 2.49… Perhaps somebody who is an expert in 2.5x can tell you if working OK or not :wink:

Regards,