#!BPY """ Name: 'BPy Doc Browser' Blender: 237 Group: 'System' Tip: 'Browse BPython (scripting API) modules doc strings.' """ __author__ = "Daniel Dunbar" __url__ = ("blender", "elysiun") __version__ = "1.0" __bpydoc__ = """\ The "Doc Browser" lets users navigate the documentation strings of part of the Blender Python API. It doesn't give access yet to object method functions and variables, only to module functions, but still it is a handy reference. Hotkeys:
Qkey and ESCkey to quit. Notes:
Everyone interested in the bpython api is also invited to read "The Blender Python API Reference" doc, available online ("Python Scripting Reference" entry in Blender's Help menu). """ ##### # Blender help browser # By Daniel Dunbar, ddunbar@diads.com # # This should function as a self-explanatory (interface, not code) # (mostly) help browser. The code is wacky and nasty and or fun, # but mainly bad, just cause it works doesn't mean its readable! # # TEEHEE! # # The row_draw function could easily be made into a more generic # and usefull table drawing function... # import Blender from types import ListType, IntType, FloatType, StringType, ModuleType from Blender.Draw import * from Blender.BGL import * # Simple version check, since I use the # buffer calls... DONT use this code, # assume everyone has 1.73+, and force # them to upgrade if they dont try: a= BufList version= 172 except: version= 173 # I could have used the split from the string module, # but some people might not have it def split(str, on): out= [""] for s in str: if s in on: out.append("") else: out[-1]= out[-1]+s if out[-1]=="": del(out[-1]) return out last_sort= 1; direction= 1 def sort_browselist(type): global browselist global last_sort, direction if (type==last_sort): direction= -direction else: direction= 1 last_sort= type if (direction==1): def byname(x, y): return cmp(x[0],y[0]); def bytype(x, y): return cmp(x[1],y[1]) def bydata(x, y): return cmp(x[2],y[2]) else: def byname(x, y): return cmp(y[0],x[0]); def bytype(x, y): return cmp(y[1],x[1]) def bydata(x, y): return cmp(y[2],x[2]) if (type==1): browselist.sort(byname) elif (type==2): browselist.sort(bytype) elif (type==3): browselist.sort(bydata) selected= -1 def view_doc(num): global selected, selected_page if (selected==num): selected= -1 else: selected= num selected_page= 0 function_filter= 0 def toggle_function_filter(): global function_filter function_filter= not function_filter make_browselist() def view_page(dir): global selected_page selected_page= selected_page + dir browse_scrollstart= 0 def browse_module(num): global browsing, selected, browse_scrollstart if (num>=0): newstr= browsing.val + "." + browselist[num][0] else: modules= split(browsing.val, ".") newstr= "" for m in modules[:-1]: newstr= newstr+m try: browsing= Create(newstr) make_browselist() except: browsing= Create('Blender') make_browselist() browse_scrollstart= 0 scrolling= 0 selected= -1 def make_browselist(): global browselist browselist= [] module= eval(browsing.val) items= dir(module) for item_name in items: if (item_name[:2]=='__'): continue data= [item_name, 'None', '', ''] item= eval(item_name,module.__dict__) t= type(item) if (t==IntType): data[1]= 'Int'; data[2]= `item` elif (t==FloatType): data[1]= 'Float'; data[2]= `item` elif (t==StringType): data[1]= 'String' elif (t==ModuleType): data[1]= 'Module' elif (callable(item)): data[1]= 'Function' doc= item.__doc__ if (doc): data[3]= doc if (function_filter and data[1]!='Function'): continue browselist.append(data) browsing= Create('Blender') make_browselist() BROWSE_EVT= 1 SORT_BYNAME= 2 SORT_BYTYPE= 3 SORT_BYDATA= 4 DOC_PAGE_UP= 5 DOC_PAGE_DOWN= 6 BACK_MODULE= 7 CLOSE_VIEW= 8 FILTER_DISPLAY= 9 VIEW_DOC= 100 BROWSE_MODULE= 15000 browse_scrollstart= 0 scrolling= 0 scrollstep= 0 scrolling_start= 0 def do_scrollbar(pos, val): global scrolling, scrolling_start, browse_scrollstart if (scrolling): if (not val): scrolling= 0 Redraw() else: d= scrolling_start-pos[1] if (abs(d) > scrollstep): if (d>0): if(browse_scrollstart0): browse_scrollstart= browse_scrollstart+int(d/scrollstep) scrolling_start= pos[1] Redraw() elif (val!=-1): if (scrollrect[0] < pos[0] < scrollrect[2]): if (scrollrect[1] < pos[1] < scrollrect[3]): scrolling= val scrolling_start= pos[1] Redraw() winrect= [0.0, 0.0, 0.0, 0.0] def draw(): global browsing, winrect # Blender doesn't give us direct access to # the window size yet, but it does set the # GL scissor box for it, so we can get the # size from that. if (version<173): size= Buffer(GL_FLOAT, None, 4) glGetFloat(GL_SCISSOR_BOX, size) size= BufList(size) else: size= Buffer(GL_FLOAT, 4) glGetFloatv(GL_SCISSOR_BOX, size) size= size.list winrect= size[:] size[0]= size[1]= 0.0 size=map(int,size) # Shrink the size to make a nice frame # (also a good technique so you can be sure you are clipping things properly) size[0], size[1]= size[0]+10, size[1]+10 size[2], size[3]= size[2]-12, size[3]-10 glClearColor(0.6, 0.5, 0.3, 0.0) glClear(GL_COLOR_BUFFER_BIT) # The frame glColor3f(0.4, 0.5, 0.2) glRectf(size[0], size[1], size[2], size[3]) # Window header glColor3f(0.2, 0.2, 0.4) glRectf(size[0], size[3]-25, size[2], size[3]) glColor3f(0.6, 0.6, 0.6) glRasterPos2f(size[0]+15, size[3]-17) Text("Zr's Help Browser") Button("Filter", FILTER_DISPLAY, size[2]-400, size[3]-22, 45, 18) Button("Back", BACK_MODULE, size[2]-300, size[3]-22, 45, 18) browsing= String("Browse: ", BROWSE_EVT, size[2]-250, size[3]-22, 245, 18, browsing.val, 30) # The real table def row_draw(rect, data, cols, cell_colors, text_colors): if (len(data)!=len(cols)): print "Must have same length data and columns" return if (type(cell_colors)!=ListType): cell_colors= [cell_colors] if (type(text_colors)!=ListType): text_colors= [text_colors] sx= rect[0] for i in range(len(data)): d= data[i] c= cols[i] c, align= c[0], c[1] if (type(c)==FloatType): c= c*(rect[2]-rect[0]) ex= sx + c color= cell_colors[i%len(cell_colors)] apply(glColor3f, color) glRectf(sx, rect[1], ex, rect[3]) color= text_colors[i%len(text_colors)] apply(glColor3f, color) if (type(d)==StringType): str_width= len(d)*8 if (align=='left'): glRasterPos2f(sx+3, rect[1]+5) elif (align=='center'): glRasterPos2f((sx+ex)/2 - str_width/2 +3, rect[1]+5) elif (align=='right'): glRasterPos2f(ex - str_width -3, rect[1]+5) Text(d) else: d([sx, rect[1], ex, rect[3]]) sx= ex # Some colors black= (0.0, 0.0, 0.0) white= (1.0, 1.0, 1.0) red= (0.8, 0.1, 0.1) gray0= (0.17, 0.17, 0.17) gray1= (0.25, 0.25, 0.25) gray2= (0.33, 0.33, 0.33) gray3= (0.41, 0.41, 0.41) gray4= (0.49, 0.49, 0.49) gray5= (0.57, 0.57, 0.57) gray6= (0.65, 0.65, 0.65) cols= [[.3, 'left'], [.2, 'left'], [.4, 'right'], [.1, 'center']] header= [size[0]+20, size[3]-60, size[2]-40, size[3]-40] def sort_byname(co): co=map(int,co) Button("Name",SORT_BYNAME, co[0]+3, co[1], co[2]-co[0]-4, 19) def sort_bytype(co): co=map(int,co) Button("Type",SORT_BYTYPE, co[0]+3, co[1], co[2]-co[0]-4, 19) def sort_bydata(co): co=map(int,co) Button("Data",SORT_BYDATA, co[0]+3, co[1], co[2]-co[0]-4, 19) row_draw(header, [sort_byname, sort_bytype, sort_bydata,'Link'], cols, [gray0, gray1], gray6) if (selected!=-1): table= [size[0]+20, size[1]+220, size[2]-40, size[3]-60] else: table= [size[0]+20, size[1]+20, size[2]-40, size[3]-60] row_height= 25 items= (table[3]-table[1])/row_height if (items>len(browselist)): items= len(browselist) # The scrollbar (I wasn't gonna take the time to make it look nice ;) global scrollrect, scrollstep, scrolling scrollrect= [table[2]+5, table[1], table[2]+25, table[3]] apply(glColor3f, gray6) glRectf(scrollrect[0], scrollrect[1], scrollrect[2], scrollrect[3]) sr= [scrollrect[0]+2, scrollrect[1]+2, scrollrect[2]-2, scrollrect[3]-2] apply(glColor3f, gray3) glRectf(sr[0], sr[1], sr[2], sr[3]) height= sr[3]-sr[1] l= len(browselist) l= float(l) sh= browse_scrollstart/l eh= (browse_scrollstart+1)/l scrollstep= height/items sr= [sr[0]+1, sr[3]-eh*height, sr[2]-1, sr[3]-sh*height] if (scrolling): apply(glColor3f, gray1) else: apply(glColor3f, gray5) glRectf(sr[0], sr[1], sr[2], sr[3]) if (scrolling): apply(glColor3f, gray1) else: apply(glColor3f, gray4) glRectf(sr[0]+1, sr[1]+1, sr[2]-1, sr[3]-1) row= table row[1]= row[3]-row_height start= browse_scrollstart if (start+items>len(browselist)): items= len(browselist)-start for i in range(items): i= start+i data= browselist[i][:] if (i%2): colors= [gray1, gray2] else: colors= [gray2, gray3] # Strange pythonic code def view_doc(co,num=i): co=map(int,co) Button("Doc",VIEW_DOC+num, co[0]+3, co[1]+2, co[2]-co[0]-4, 19) def browse_module(co,num=i): co=map(int,co) Button("Browse",BROWSE_MODULE+num, co[0]+3, co[1]+2, co[2]-co[0]-4, 19) if (data[1]=='Function'): if data[3]: data[3]= view_doc tcolor= black else: tcolor= red data[2]= 'NO DOC STRING' data[3]= '' else: if (data[1]=='Module'): data[3]= browse_module else: data[3]= '' tcolor= black row_draw(row, data, cols, colors, tcolor) row[1]= row[1]-row_height row[3]= row[3]-row_height if (selected!=-1): table= [size[0]+20, size[1]+20, size[2]-40, size[1]+180] apply(glColor3f, gray5) glRectf(table[0], table[3], table[2], table[3]+20) apply(glColor3f, gray2) glRectf(table[0], table[1], table[2], table[3]) apply(glColor3f, black) glRasterPos2f(table[0]+3, table[3]+5) Text("Function: " + browsing.val + "." + browselist[selected][0]) Button("Close", CLOSE_VIEW, table[2]-50, table[3], 45, 18) row_height= 20 view_lines= int((table[3]-table[1])/row_height)-1 lines= split(browselist[selected][3], "\n") doc_lines= len(lines) sindex= view_lines*selected_page eindex= view_lines*(selected_page+1) if (sindex>0): sindex= sindex-1 eindex= eindex-1 lines= lines[sindex:eindex] y= table[3]-20 for line in lines: glRasterPos2f(table[0]+3, y) Text(line) y= y-20 if (sindex): Button("Page up", DOC_PAGE_UP, table[2]-100, table[3]-20, 90, 18) elif (eindex=len(browselist)): browse_scrollstart= len(browselist)-1 Redraw() def bevent(evt): if (evt==BROWSE_EVT): make_browselist() elif (evt==SORT_BYNAME): sort_browselist(1) elif (evt==SORT_BYTYPE): sort_browselist(2) elif (evt==SORT_BYDATA): sort_browselist(3) elif (evt==DOC_PAGE_UP): view_page(-1) elif (evt==DOC_PAGE_DOWN): view_page(1) elif (evt==BACK_MODULE): browse_module(-1) elif (evt==CLOSE_VIEW): view_doc(-1) elif (evt==FILTER_DISPLAY): toggle_function_filter() elif (evt>=BROWSE_MODULE): browse_module(evt-BROWSE_MODULE) elif (evt>=VIEW_DOC): view_doc(evt-VIEW_DOC) Redraw() Register(draw, event, bevent)