Drop Down box GUI element

Well I spent quite some time coding a drop down box class for use in bpy GUI’s. So I hope someone else can take advantage of it.

It’s relatively simple to operate, just create an instance of the box. Then call its draw() method in the UI draw callback. In the event handler callback, you need to check if the dropdown is active, (dropdown.active = 1), if it is, call the control_handler() method and return from the event handler. Something like as follows:


dropbox = drop_down(x, y, width, height, 'opt1 | opt2 | opt3 | ...')

def draw():
     global dropbox
     dropbox.draw()
     .....

def evt(evt, val):
    global dropbox
    if evt == 0: return
    if dropbox.active:
        dropbox.control_handler()
        return
    .....

def bevt(evt):
    pass

Blender.Draw.Register(draw, evt, bevt)

The drop down is all OpenGL drawn, and shouldnt interfere with anything else, though a normal Draw module interface element will draw over the top of it, so beware of that. In all likelihood it could be coded more efficiently or something but there it is :smiley:

The drop down box class:


class drop_down:
	
	def __init__(self, x, y, w, h, itemstr):
		self.x = x
		self.y = y
		self.w = w
		self.h = h
		self.active = 0
		self.items = itemstr.split("|")
		for item in self.items:
			item = self.text_clip(item)
		self.sel = self.items[0]
		self.tmp = self.sel
		self.numitems = len(self.items)
		self.button = tex_button(x + w - h, y + 1, h - 1, h - 2)
		self.sel_draw = 0
		self.z = 0
			
	def text_clip(self, text):
		pix_len = Blender.Draw.GetStringWidth(text)
		if pix_len > 160:
			tmpstr = ""
			for x in range(len(text)):
				if Blender.Draw.GetStringWidth(tmpstr) < 150:
					tmpstr += text[x]
				else:
					tmpstr += ".."
					return tmpstr
		return text	
	
	def draw(self):
		
		self.button.x = self.x + self.w - self.h
		self.button.y = self.y + 1
								
		Blender.BGL.glColor3f(0.3,0.3,0.3)
		Blender.BGL.glRecti(self.x, self.y, self.x + self.w, self.y + self.h)
		#light rect
		Blender.BGL.glColor3f(0.7,0.7,0.7)
		Blender.BGL.glRecti(self.x + 1, self.y, self.x + self.w, self.y + self.h - 1)
		#main rect
		Blender.BGL.glColor3f(0.6,0.6,0.6)
		Blender.BGL.glRecti(self.x + 1, self.y + 1, self.x + self.w - 1, self.y + self.h - 1)
		self.button.draw()
		Blender.BGL.glColor3f(0.3, 0.3, 0.3)
		Blender.BGL.glBegin(Blender.BGL.GL_POLYGON)
		Blender.BGL.glVertex2i(self.x + self.w - 16, self.y + self.h - 6)
		Blender.BGL.glVertex2i(self.x + self.w - 4, self.y + self.h - 6)
		Blender.BGL.glVertex2i(self.x + self.w - 10, self.y + 6)
		Blender.BGL.glEnd()
		
		if not self.active:
			
			Blender.BGL.glColor3f(0.2, 0.2, 0.2)
			Blender.BGL.glRasterPos2i(self.x + 4, self.y + 6)
			Blender.Draw.Text(self.sel)
		
		else:
			Blender.BGL.glColor3f(0.4, 0.4, 0.4)
			Blender.BGL.glRecti(self.x, self.y - self.numitems * 24, self.x + self.w, self.y)
			Blender.BGL.glColor3f(0.6, 0.6, 0.6)
			Blender.BGL.glRecti(self.x + 1, self.y - self.numitems * 24 + 1, self.x + self.w - 1, self.y)
			Blender.BGL.glColor3f(0.2, 0.2, 0.2)
						
			z = 0
			for item in self.items:
				Blender.BGL.glColor3f(0.2, 0.2, 0.2)
				Blender.BGL.glRasterPos2i(self.x + 6, self.y + 6 - (z+1) * 24)
				Blender.Draw.Text(item)
				z += 1
				
			if self.sel_draw:
				Blender.BGL.glColor3f(0.2, 0.2, 0.2)
				Blender.BGL.glRecti(self.x + 1, self.y -self.z * 24 + 1, self.x + self.w - 1, self.y - self.z * 24 + 20)
				Blender.BGL.glColor3f(0.8, 0.8, 0.8)
				Blender.BGL.glRasterPos2i(self.x + 6, self.y + 6 - (self.z) * 24)
				Blender.Draw.Text(self.tmp)
				
	def control_handler(self, evt, val):
		if evt == Blender.Draw.RIGHTMOUSE or evt == Blender.Draw.ESCKEY:
			self.active = 0
		
		if evt == Blender.Draw.MOUSEY or evt == Blender.Draw.MOUSEX:
			x, y = area_mouse_coords()
			if not (self.x < x < self.x + self.w or self.y - self.numitems * 24 + 1 < y < self.y):
				self.sel_draw = 0
				self.active = 0
				return
			
			self.sel_draw = 1
			x, y = area_mouse_coords()
			self.z = (self.y - y + 18) / 24
			if self.z > 4:
				self.z = 4
			if self.z < 1:
				self.z = 1
			self.tmp = self.items[self.z-1]
			
		if evt == Blender.Draw.LEFTMOUSE and val == 0:
			self.sel = self.tmp
			self.active = 0
			
		Blender.Draw.Redraw()

Let me know if you make any use of this.

timmeh

[EDIT]

It appears you also need the tex_button class :slight_smile: so here it is:

class tex_button:

	def __init__(self, x, y, width, height):
		
		self.x = x
		self.y = y
		self.h = height
		self.w = width
		self.pushed = 0
	
	def move(self, x, y):
		self.x = x
		self.y = y
	
	def draw(self):	
	
		Blender.BGL.glColor3f(0.7,0.7,0.7)
		Blender.BGL.glRecti(self.x, self.y, self.x + self.w, self.y + self.h)
		#light rect
		Blender.BGL.glColor3f(0.4,0.4,0.4)
		Blender.BGL.glRecti(self.x + 1, self.y, self.x + self.w, self.y + self.h - 1)
		#main rect
		if self.pushed:
			Blender.BGL.glColor3f(0.3,0.3,0.3)
		else:
			Blender.BGL.glColor3f(0.6,0.6,0.6)
		Blender.BGL.glRecti(self.x + 1, self.y + 1, self.x + self.w - 1, self.y + self.h - 1)

Looks very useful! Will it work in a regular 3d window (using a draw space handler)?

well i havent really used space handlers, but i imagine so since all the drawing is opengl based.

-timmeh