New "Draw" functions -- Multi-value defaults

I’ve got a new project in the works but am not entirely satisfied with the stock set of Buttons. And by that I mean there are some controls that I want that are not yet available.

I’ve just finished some initial tests and am ready to start coding the initial version. I want to eventually put all these new controls into an include-able module.

First up is the ImageButton. Each click of the ImageButton will change the image and the object value. Typical use would be for two values (like a toggle) but three or more will be allowed as well. Per button callbacks and an event “hook” will complete what is needed for its use.

Future additions will likely include Scroll bars and perhaps a Tree View (even though I tend to eschew Tree Views). We’ll see on that one.

Here is the first sample code and sample video (I borrowed some icons from the outliner):

Sample Video (196 KB, DivX)

And screen snippet:
http://www.fourmadmen.com/blender/misc/DrawX_demo.jpg


stockIcons1 = Image.Load("some_icons.tif")
stockIcons1.reload()
buttons = [DrawX.Create(0), DrawX.Create(1), DrawX.Create(0), Draw.Create(0), Draw.Create(0)]

def event(evt, val):
    if evt == Draw.ESCKEY:
        Draw.Exit()                 # exit when user presses ESC
        return
        
    Draw.Redraw(1)
#end event

def button_event(evt):
    
    if evt==111:
        print "clicked 111 button"
    elif evt==222:
        print "clicked 222 button"
    elif evt==333:
        print "clicked 333 button"
    elif evt==444:
        print "clicked 444 button"
    #end if
    
    Draw.Redraw(1)
#end button_event    

def gui():
    global stockIcons1, buttons
    
    buttons[0] = DrawX.ImageButton("", 111, stockIcons1, 110, 100, 16, 16, 2, buttons[0].val, 0, 0)
    buttons[1] = DrawX.ImageButton("", 222, stockIcons1, 126, 100, 16, 16, 2, buttons[1].val, 16, 0)
    buttons[2] = DrawX.ImageButton("", 333, stockIcons1, 142, 100, 16, 16, 2, buttons[2].val, 32, 0)
    buttons[3] = Draw.Toggle(" ", 444, 160, 100, 16, 16, buttons[3].val)
    buttons[4] = Draw.Number("Num", 555, 180, 100, 70, 16, buttons[4].val, 0, 4)


# register the three callbacks (Registers Blender's Draw callbacks and hooks into them)
DrawX.Register(gui, event, button_event)


The ImageButton allows for multiple states (values). The tests so far are only for two values (0 and 1) but there could be as many as you want.

The icon file looks like this (sans Alpha Channel):
http://www.fourmadmen.com/blender/misc/some_icons.jpg

First value state images are on the bottom. Second value state is up one more, etc. etc. The clipping is computed for the additional states, so as the value changes so does what you see on the screen. A three state button would have a column of three stacked images.

The twist for event handling is that the mouse clicks are handled by the “event” call back but for buttons it’s the “button_event” callback. So I had to create a hook into the callback “stream” which essentially (on the clicking in the area of the ImageButton) cross-feeds the event callback to the button_event.

looks good

I welcome anything that improves the python UI options

the addition of icons would be great, as would be a scroll bar

would it be possible to have zoom in the script window?

looks very promising!
With the functionality it will be possible to make clearer ergonomic UI layouts
Is it a pluggable solution? python-only code? release date?

A zoom could be implemented reasonably easily but would require the DrawX module to hook into all the Draw module functions. Conversion of the resulting float types into integers might cause some “oddities” in the positions of controls relative to the other controls in a UI. Worth looking into though.

This is pure python. And at present does not require a full python install to run. The project I’m working on has a projected release of sometime in December so this will have to go out at the same time. If the widget work goes long it might be January but we’ll see. What goes out then will have at least the controls that my current project will need.

When I get a little further along I’ll probably put a call out for beta testing. But more on that later.

Following on from this and the SOC automation work something I would like is a sort of parametric mode to create a script UI where you could drag in generic Draw elements and resize and position them + snap to a grid position to make a neat interface easily.

The ability to reenter this mode after the script is written to reposition or refine things as a script develops over time or even allow users to redo the layout to suit their preferences or their particular screen layout would be great.

It would be handy if this mode could include a wrap type feature too so you could drag the overall window display to have a horizontal or vertical orientation and have the Draw elements reposition themselves. :slight_smile:

Another thing that could be useful is to have some ‘dials’ and ‘meters’ available.

In the script version I modified for Indigo I made a crude ‘LED’ match meter for light exposure as you would see in a camera viewfinder.

It is possible other folks might like a UI suited to a mixing desk for instance or perhaps to interact with the 3d window or GE events for cockpit display or such… dunno just thinking out loud there… :wink:

will be happy with anything anyone adds - unfortunately I dont have the coding skills myself

Please do. Do you have any images as examples of these controls?

While it does not handle the user layout question there used to be a program (not running in Blender) where you could drag and drop controls and then auto generate the Blender Python GUI code.

Auto-layout configuration could be possible by creating layout container objects that know how to reconfigure the controls they contain based upon width/height of the script window (or user “control”). Easy to say and not impossible to implement but to be accepted would need a fair amount of time and thought about how it might work from a scripting and useability perspective.

I am aware of that program (and I think there was another also) but at the time - possibly a couple of years ago since they were done - I couldnt understand how to set it up with my level of knowledge :o Probably a lot of people would fall in that category

If possible I would rather access something intuitive/straight forward built into Blender sorta like ‘edit’ and ‘object’ mode but for scripts.
Maybe that program could be gutted for building into Blender?

I’ll see what I can do to make an illustration of what I mean for dials and meters

EDIT: ok here is an initial attempt at some - most likely other people have better ideas

the dial is resizeable a bit like the existing sphere input and has min/max
the meter is a bit like that too and the LED you can specify the number of segments

http://img504.imageshack.us/img504/4290/dialsph7.jpg

and here is the lower portion of my Indigo script version with the improvised light meter on the right side
the green LED moves up/down the scale and is red at over/under scale
the blue LED on the edge provides the match clue for different situations

http://img395.imageshack.us/img395/3910/screenox9.jpg

maybe these will stimulate some discussion about some new Draw options as well as the stuff you (@FourMadMen) are pursuing :wink: HTH

First things first:

VerticalScrollbar - This will be a visible control, obviously, but it will also be a container that holds a list of other controls. Population of this list is optional and affects the usage as follows:

With an empty object list the scrollbar will simply return an offset value that script authors can use to manually offset the elements of their GUI.

With a populated object list the scrollbar will at draw time automatically offset the GUI elements (see footnote 1). This has a few advantages:

  • The script author will not have to write any additional code for the scrolling itself.
  • Controls that are entirely outside the visible area need not be drawn at all.
  • Not all objects would have to be added to the list. Thus allowing for part of the UI to scroll and the rest to remain static (see footnote 2).
  • The UI if needed could have more than one vertical scrollbar that scrolls a different set of objects for whatever reason (see footnote 2 again).

Footnotes:

  • Since the Button objects returned by Blender do not expose the Y value of the control the DrawX module would, at the very least, have to be a proxy for any script window control that has a Y value (Popup objects excluded of course). Ideally it would be nice if the Blender Button API exposed the X, Y, width, and height of the controls as all these would have to be tracked for an automatic Zooming implementation. But as I say, for the vertical scrolling only need to expose the Y value (or collect the Y value at Draw time using DrawX methods as a proxy).
  • Since there is no concept of clipping within the script window the vertical scrollbar would apply to the entire vertical height of the script window. This could be faked to some degree but controls that lie only partially within the scrolling area could not be drawn at all. At present this fake-clipping is outside the scope of this project.

Next… Big Fan’s examples - These types of controls were not part of my original plan as they are beyond what Blender represents in the rest of the user interface. It was not my intention to create any control that Blender itself does not have an analogue for.

However I think something can be done rather easily without having to resort to a bunch of OpenGL drawing and cries of “Hey a dial! Wait… it’s ugly I’m not going to use that!”.

So my idea is this (and you can tell me what you think)…

For the first two in your example (the pot and the dial): These I think can be achieved using a single control type. This control would take two images. One image for the control itself and a second image that acts as a mask. From the DrawX side it draws the control value graphically (dial needle or what not) and the mask limits where the drawing occurs.

The LED and Light meter example could be done in a similar way using a combination of BGL drawing and a mask (as an overlay this time). Or they might be specific enough to do something specific for them. Although these are more of a visual output rather than input devices so might be best to leave it for the script author to code themselves. The LED one could be made to look nicer by using Draw.Image to display a nice graphic for the LEDs.

Thanks for the suggestions. Too early to tell what goes in and what doesn’t but keep the ideas coming as nothing is ever completely beyond consideration.

>it’s ugly I’m not going to use that

well I can sympathise with that view but I tried to keep it simple in keeping with the appearance of the available Draw stuff :smiley:

the problem is the whole python UI is crude, ugly and limiting ( actually it fits in with the std of the rest of the Blender UI like that - but lets not go there… :wink: )

icons and a scroll bar would be a good start

>does not have an analogue for

aside from gaming and mixing desk scenarios I seem to remember there was talk of people being interested in using blender for robotics at one time
I guess there is some general need for interfacing in a way that isnt necessarily just for ‘artistic’ purposes that could be accomplished with images in the way you propose.
It would be certainy flexible that way and a large step forward from the present situation.
I hope the facility wont consume too much memory resource though…

One idea I had for the Lux render UI (and that was soundly rejected by the powers that be unfortunately) was actually to use a large real image of a digital camera back and use the LCD screen area and buttons as an underlay for the script UI.
Of course that idea was a little ahead of its time :wink: and it would have made the rest of the Blender window look even more shabby than it is :stuck_out_tongue:
However it ( the image idea) is something I have considered and used to some extent to preview IES profiles in blendigo.
If you look at the portion of the script above and how busy it is you can see why I would want a tool to edit the buttons layout easily as the script and Indigo evolved/developed.
In the beginning it was fairly simple but now it is overgrown and messy despite my efforts to make it tidy and logical - in fact I regret people with a small screen cant use it like that…such is life

Looking forward to whatever you have the generosity to share with the community :spin:

Well I didn’t specifically mean your example. Although it is not specifically excluded from that comment either :smiley:

But making these sorts of things from images 1) Keeps me from having to code the drawing commands and 2) Allows for a much nicer finished look than can easily be achieved using the drawing commands.

Inspired from the Blender Conference GUI video I have added the next new DrawX feature: “Sheets”.

Following the images and the code I will talk about where these are going in terms of scrollbars and perhaps more timely how I see these working for both Vertical and Horizontal layouts.

First here is the gui code:


def gui():
    global sheets, buttons
        
    sheets[0] = DrawX.Sheet("Transform", 1111, sheets[0].val, "Transform Widgets")
    buttons[0] = DrawX.Toggle("T1", 123, 0, 0, 20, 20, buttons[0].val)
    buttons[1] = DrawX.Toggle("T2", 124, 0, 24, 20, 20, buttons[1].val)
    
    sheets[1] = DrawX.Sheet("Display", 2222, sheets[1].val, "Display Widgets")
    buttons[2] = DrawX.Toggle("T3", 223, 0, 0, 20, 20, buttons[2].val)
    buttons[3] = DrawX.Toggle("T4", 234, 0, 24, 20, 20, buttons[3].val)


And here is how it looks.

First at startup with both expanded. The widget attribute “val” is set to 1 for both so they startout expanded but either could have been set to a value of 0 to start collapsed.

Second here is the first Sheet collapsed. Note that there is no script developer code required beyond calling DrawX.Sheet. All subsequent buttons that are drawn are associated with the active sheet until such time as either the end of the gui function or another sheet is created.

Things at this point need some cleaning up code-wise and the next step before scrollbars will be Buttons that accept a list of default values or a single default value. Multiple default values that are not all the same will cause the button to be rendered in a THIRD selection state until the button is clicked the first time. After that the button will behave as normal (you’ll have to see the Blender Conference video on the GUI for an example of this).

Scrollbars…

While I still plan a seperate scrollbar widget the “Sheets” will have their own auto scrollbars under the following conditions:

Vertical and Horizontal arrangement…

In a vertical arrangement the “Sheets” will be drawn top to bottom (Note: X and Y coordinates for drawing buttons start at the upper-left of the sheet). If the vertical size of the drawn elements goes beyond the visible portion of the area then a scrollbar will be added. In a vertical arrangement there will be at most one scrollbar drawn.

In a horizontal arrangement the “Sheets” will be draw side-by-side. Should any one sheet extend beyond the height of the area it will get it’s own scrollbar. So in a horizontal arrangement there will be at most one scrollbar or each “Sheet”.

A couple of (false color) pictures by way of example:

The green blocks show the approximate used space for each sheet. In real usage this color would be the same as the background.

http://www.fourmadmen.com/blender/misc/sheet_mockup_v.jpg

http://www.fourmadmen.com/blender/misc/sheet_mockup_h.jpg

hi fourmadmen,
I have a bag full of python gui scripts.
I’ll upload them for you soon.
hopefully you can find some good bits of code.
There really needs to be a set interface layout for all scripts.
It is good to see work towards this end.
ianwill would be good to talk to on this also.
Here is all the gui scripts I have. Gui Scripts
The pscc4_layers & toolbar script should be of interest.

here’s one for you…

http://sites.google.com/site/metaandrocto1/Home/ah_the_horror.jpg?attredirects=0

Who said script interfaces were scary?:smiley:

@FourMadMen

looks really good.

if you saw the BC videos did you understand from what was said, as I did, that the 2.50 overhaul would utilise Python for the UI drawing?
if this is to be so I wonder if you should involve yourself some in the planning for it just so that you dont code for something that might be immediately redundant or need to be done somewhat differently.
Perhaps the code for the scripts window can be exactly the same as for buttons window such that the sheets and scroll is in common with the panels and as collapsed.
( hope you understand what I am trying to say there :wink: )

that the 2.50 overhaul would utilise Python for the UI drawing?

From what I see and heard it would be nice if Fourmadmen can offer assistance in the coding project that would allow Blender’s interface to be drawn with python.

We have to look now in terms in what will be laid out for 2.5, not only so to make 2.5 a hugely successful release, but to minimize frustration among developers and to make sure all new development in 2.5 friendly.

I started this originally because I wanted to make the UIs for my Layer Manager and a new script idea have a look very similar to that of the Outliner. For that I needed ImageButtons and scroll bars.

After seeing the UI video from the Blender Conference (specifically the section on setting properties for multiple objects at the same time) I started to think about what it would take to code an interface like that with Python (i.e. collapsable “sheets”, three state toggles, etc.).

@Big Fan, I don’t specifically remember the line about 2.5 GUI being rendered with Python. It sounds familiar but I guess I didn’t listen in on it enough to say for sure. I’ll go back and re-watch it with ears towards that concept. Thanks. At present this module is as much a mental/design exercise from what is, I guess, the early stages of the 2.5 UI so I fully expect to code things here that may in fact have an analogue in 2.5. I see that as being OK given that it’s early days both for DrawX as well as UI design of 2.5.

@Meta-Androcto, Thanks for the collection. I’ll download in just a moment and look the contents over.

Also, after seeing the video, I wanted to see if I could make this Python module into something that would help script writers code a script UI that kept a near visual flavor with what may be coming in 2.5. It’s certainly WAY too early to know what it will look like, but it’s never too late to try things out and see where they lead.

With 2.5 sitting out there on the horizon I dare say anything I do with DrawX now is likely to break the 2.5 UI “mold” by the time it (Blender) is released. But at this point perhaps it more important to explore some of the possibilities even if DrawX is never used (by others or even myself).

If in fact the UI going forward is going to be rendered in Python I certainly will do what I can to help out in that regard Cyborg Dragon. If only to continue work on DrawX so some of the new concepts can be explored as a working script (rather than just static mockups). Persuant to that idea I will try to take as much time as I can in the coming week to finalize sheets and scroll bars (which is what I had planned to do anyway).

On the loss of horizontal button layout front…

I’m not instantly against that idea as I not enough design work has be done (at presented to the community) for me to make a sound judgement. I think the loss of them would be a large change for me in how I use Blender for myself and as such it would be nice if there was someway of keeping both schemes in the UI. I already do some vertical scrolling (in my otherwise horizontal layout) for long Mesh modifier lists and I don’t find that to be overly burdensome.

I do however like many of the concepts in the UI video: Context sensitivity, drag and drop, and the vertical layout that IS in the video is very nice and I could see myself happily using what I saw. I just don’t see why a method could not be implemented that would allow for both (horizontal and vertical). But as I say, I’m waiting on more design work in this regard before I can render my own final judgement on ditching horizontal layouts.

I hope it wasn’t me. If it was, I was either lying then or just don’t know what I’m getting myself into now.

I think where I heard about python being used was in Ton’s keynote.
Maybe you should contact Ton for some more details :smiley:

OK, right to it…

Got a fair bit of the clean-up I wanted done. Then decided to throw caution to the wind and start adding controls to my test script. Only had one minor issue to fix. The other 99% worked right out of the gate if I do say so myself.

Here is my test UI (I need a proper Checkbox but for now the “Outliner Eye” will do as a stand-in:

At this point I’m ready to start the auto-scrollbar implementation. And probably should. But what I REALLY want to do is code the auto-layout (H vs V) features. Ah well, I’ll try to resist that temptation for now and stick with scrolling.

http://www.fourmadmen.com/blender/misc/DrawX_demo3b.jpg


def gui():
	global testIcons1
	global sheets, transform_butons, display_butons
	global buttons
	
	sheets[0] = DrawX.Sheet("Transform", 1111, sheets[0].val, "Transform Widgets")
	
	x = 10
	DrawX.Label("Location", x+15, 5, 60, 10)
	transform_buttons[0] = DrawX.Number("X:", 100, x, 20, 90, 20, transform_buttons[0].val, -10000.0, 10000.0, "Location X")
	transform_buttons[1] = DrawX.Number("Y:", 101, x, 45, 90, 20, transform_buttons[1].val, -10000.0, 10000.0, "Location Y")
	transform_buttons[2] = DrawX.Number("Z:", 102, x, 70, 90, 20, transform_buttons[2].val, -10000.0, 10000.0, "Location Z")
	transform_buttons[3] = DrawX.PushButton("Clear", 103, x, 95, 90, 20, "Clear Location")
	
	x = 115
	DrawX.Label("Rotation", x+15, 5, 60, 10)
	transform_buttons[4] = DrawX.Number("X:", 200, x, 20, 90, 20, transform_buttons[4].val, -10000.0, 10000.0, "Rotation X")
	transform_buttons[5] = DrawX.Number("Y:", 201, x, 45, 90, 20, transform_buttons[5].val, -10000.0, 10000.0, "Rotation Y")
	transform_buttons[6] = DrawX.Number("Z:", 202, x, 70, 90, 20, transform_buttons[6].val, -10000.0, 10000.0, "Rotation Z")
	transform_buttons[7] = DrawX.PushButton("Clear", 203, x, 95, 90, 20, "Clear Rotation")
	
	x = 220
	DrawX.Label("Scale", x+15, 5, 60, 10)
	transform_buttons[8] = DrawX.Number("X:", 300, x, 20, 90, 20, transform_buttons[8].val, -10000.0, 10000.0, "Scale X")
	transform_buttons[9] = DrawX.Number("Y:", 301, x, 45, 90, 20, transform_buttons[9].val, -10000.0, 10000.0, "Scale Y")
	transform_buttons[10] = DrawX.Number("Z:", 302, x, 70, 90, 20, transform_buttons[10].val, -10000.0, 10000.0, "Scale Z")
	transform_buttons[11] = DrawX.PushButton("Clear", 303, x, 95, 90, 20, "Clear Scale")
		
	sheets[1] = DrawX.Sheet("Display", 2222, sheets[1].val, "Display Widgets")
	
	#Draw.BeginAlign()
	display_buttons[0] = DrawX.Toggle("Shaded", 500, 10, 10, 80, 20, display_buttons[0].val)
	display_buttons[1] = DrawX.Toggle("Solid", 501, 90, 10, 80, 20, display_buttons[1].val)
	display_buttons[2] = DrawX.Toggle("Wireframe", 502, 170, 10, 80, 20, display_buttons[2].val)
	display_buttons[3] = DrawX.Toggle("Bounds", 503, 250, 10, 80, 20, display_buttons[3].val)
	#Draw.EndAlign()
	
	DrawX.Label("Extras:", 10, 40, 60, 10)
	#DrawX.Checkbox...
	display_buttons[4] = DrawX.ImageButton("Name", 510, testIcons1, 15, 55, 16, 16, 2, display_buttons[4].val, 0, 0)
	display_buttons[5] = DrawX.ImageButton("Axis", 511, testIcons1, 15, 75, 16, 16, 2, display_buttons[5].val, 0, 0)
	display_buttons[6] = DrawX.ImageButton("Wireframe", 512, testIcons1, 15, 95, 16, 16, 2, display_buttons[6].val, 0, 0)
	display_buttons[7] = DrawX.ImageButton("Transparency", 513, testIcons1, 15, 115, 16, 16, 2, display_buttons[7].val, 0, 0)
	display_buttons[8] = DrawX.ImageButton("X-Ray", 514, testIcons1, 15, 135, 16, 16, 2, display_buttons[8].val, 0, 0)
	display_buttons[9] = DrawX.ImageButton("Texturespace", 515, testIcons1, 15, 155, 16, 16, 2, display_buttons[9].val, 0, 0)
	
	sheets[2] = DrawX.Sheet("Test1", 3333, sheets[2].val, "Test1 Widgets")
	
	buttons[0] = DrawX.ImageButton("View", 111, testIcons1, 0, 0, 16, 16, 2, buttons[0].val, 0, 0)
	buttons[1] = DrawX.ImageButton("", 222, testIcons1, 16, 16, 16, 16, 2, buttons[1].val, 16, 0)
	buttons[2] = DrawX.ImageButton("", 333, testIcons1, 32, 32, 16, 16, 2, buttons[2].val, 32, 0)
	buttons[3] = DrawX.Toggle(" ", 444, 50, 48, 16, 16, buttons[3].val, "My test Toggle")
	buttons[4] = DrawX.Number("Num", 555, 70, 48, 70, 16, buttons[4].val, 0, 4, "My test Number")
	
	sheets[3] = DrawX.Sheet("Test2", 4444, sheets[3].val, "Test2 Widgets")
	
	buttons[5] = DrawX.Toggle("T1", 223, 0, 0, 20, 20, buttons[5].val)
	buttons[6] = DrawX.Toggle("T2", 234, 0, 24, 20, 20, buttons[6].val)

I wonder if you can extend your sheet concept slightly…
At times it would be quite handy to have a script in a ‘flyout’ window (or scripts in parallel windows collapsed but for one) |||
These would be provide ancillary function space but be quickly accessible to the work and not take up much space otherwise.
Basically this would be a window as we know it but of min width of say 30 pixels - a bar if you like - just enough to display the script title and an arrow
When this is clicked on/toggled the script window expands to full size inwards be it up/down /sideways to reveal the whole script with any sheets :eyebrowlift:

Are you talking about changing the size of the sciprt window(s)? Can you provide some pictures of what you mean?