Draw on-top of Button control

Hi!

Is it possible to draw on-top of a button (button control)? I was even thinking of using a CustomControl but it seems that one cannot draw on-top of a generic button ("frame=1" option), or am I mistaken? I know that I can use a custom picture for the buttons but I would prefer to use the generic button because I have already put a lot of effort in a programmatic drawing of specific items in IGOR ... I would be happy for any ideas, solutions for this rather specific issue. Thanks!

Best regards,
Gregor
Buttons are always drawn on top.

You say that "I know that I can use a custom picture for the buttons but I would prefer to use the generic button because I have already put a lot of effort in a programmatic drawing of specific items in IGOR". Is this a dynamic, run-time generated picture? If it is something that can be drawn once and saved, then you could make a ProcPicture from it that can be saved with your code and then used as the picture for a button. Draw the picture into a graph or panel window, copy it, go to Misc->Pictures to load it from the clipboard, and click Copy Proc Picture. That puts code into the clipboard that can be pasted into a procedure file.

If you must draw it at runtime, then a custom control is your only option.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
Here is an example to illustrate what John may have in mind. It is a greatly stripped down version from Igor's Manual example on p. III-374 dealing with custom controls.
#pragma rtGlobals=1     // Use modern global access method.
    static constant kCCE_mousedown= 1
    static constant kCCE_mousemoved= 4
    static constant kCCE_draw= 10
    static constant kCCE_drawOSBM= 17
    // PNG: width= 177, height= 120

    Picture drawButton
    ASCII85Begin
    M,6r;%14!\!!!!.8Ou6I!!!#(!!!"E#Qau+!;Z+c9)nql&TgHDFAm*iFE_/6AH5;7DfQssEc39jTBQ
    =U"
3X8(5u`*!mG6$QUEC+5i?G0Agc'Em3!N$NM#7s-^X[.(1Wf"cPFU4Ko.7duc6`MW3)A%2lN`MGb
    j.Df;q^3GU)V_]Iq*o+T"
Npj\GqV`lY!Wc-@?7<;V:S\FSad9ejML5D:T8=_'A=1GrFKsIL3L@_(T^
    #aNZp?7[pWp0'$JbI50?l#W78DQ=6Tr;jS$fRCZd?eqDa-N1%PSg3,;uFkS\2S0NV&DOTk*5bH3^'8
    !`(Su*n(a/>n"-O:n^jaCgU-:YV?aKF5X;POP5aJI1t.+lJrQ^?fu^2P[P"G<D.6=V6i'C6nnbJ)<D
    Hn@r%ojtmEc.N4c[$!A+CeYI/>8acgYb,;nBh+IpkG'B&_5<!!Uc6,!@9iBr8E,)M+RDbX@AG_G&A:
    WXicYt<d?fM;mPR9A4h@-%N@"q*?am=sD1WmV(S=,q'*Rh8O]bpJ5nIrIPJos("S"[B=Z#p12N0_5J
    g'YbkG*Vh!UXM5%#K0i)&:APEW+&>\-[o.a:=X]LiFDp$J#]#\d=,0B_J3Q3<>\iV?qt[KK0&d*#7?
    X(_Z>*'@<$l(_Tr;&*=!ORXjP_H"
Q$Nb"WOj!ZFcuUBtb\e&3>iJB"+07MF-^!ZFcuUBtTj!KAG!d0
    ):pJ4:4!BEB)H5beX!T6["KT8Oo/SA5?d]u'l>JG'Qe[M0!%-h-59%7ClVQ6o]tY[U@8Z//E>-D5dV
    @/1XBGiMBX"
LLl:N/B?h]@/M_T]md?'r0I>_YRY8OMs0hmqL)$!U[B'7`>WCLP22A$*kB`CWE)s%1,
    %5Jl+6Lk/<'NL4iei_5J1^F(.,l6UG7N?rXe\AIoJ7-ck9f@Y0^:[=^#V(E%n]g/!f!^Z'm-]6d5Wk
    g?LT,iQ=e/GaBG#k@ZX83)mo%s;+>IruE2ho$k-+/TI1P&"0Kr(.RF+Xk6eLG^UfH/?J[+Dr=P>/Jk
    L:q$,,fmC/m.gX8oGm@KZOtd6arYZPUe<`*"
agdtq*0a`A'j5^E#DXnY`,]P6.&KfMbJD@ZZ(/Tirt
    "+6DI&Te^1tWVpn!>#eRu2V)h+BW=qebfnj'T*UiI-l.2`tH'\teiT<WhY65Is`Ned'pRku;)hG[NN
    [_atJgAJt!C1?cWL@:m_#9aaTKLX^Of&&)b1=q1<65]uCn;K9aKklS<T8<=haQt^$\d>4RD25*M6DU
    3A#T8-8][!"
nL%O*;b1b.Yln0GfpJ#mIkAf^22_eYKH,9+J&(6;>I/-\be,TIK!(fUS7'8jaJc
    ASCII85End
End

Function drawscale(vmin,vmax,n)
    Variable vmin,vmax,n
    variable i
    Variable theta0= 2.39 // Note: constants are specific to panel button image
    Variable dtheta= -1.67/n
    Variable x00= 90, y00= 120,len= 85,ticklen=10,labellen=15
    String s
    SetDrawEnv textxjust= 1,textyjust= 1,save
    for(i=0;i<=n;i+=1)
        Variable theta= theta0 + i*dtheta
        Variable x0= x00 + len*cos(theta)
        Variable y0= y00 - len*sin(theta)
        sprintf s,"%.2g",vmin+i*(vmax-vmin)/n
        DrawLine x0,y0,x00 + (len+ticklen)*cos(theta),y00- (len+ticklen)*sin(theta)
        DrawText x00 + (len+labellen)*cos(theta),y00 - (len+labellen)*sin(theta),s
        if( i!=n )
            DrawLine x0,y0,x00 + len*cos(theta+dtheta),y00 - len*sin(theta+dtheta)
        endif
    endfor
End

Function MyCC_ButtonFunc(s)
    STRUCT WMCustomControlAction &s
    if( s.eventCode==kCCE_drawOSBM )
        drawscale(0,10,10)
    elseif( s.eventCode==kCCE_mousedown )
        beep
    endif
    return 0
End

Window Panel0() : Panel
    PauseUpdate; Silent 1 // building window...
    NewPanel /W=(150,50,350,200)
    CustomControl cc3,pos={10,10},proc=MyCC_ButtonFunc
    // This should be after the setting of the proc
    CustomControl cc3,picture= {ProcGlobal#drawButton,1}
EndMacro

The Procedure picture (created previously with the drawing tools) is the "button" outline, and the Igor drawing stuff is found in the drawscale( ) function. That is where you could put your own drawing routines. The extra necessary item is the MouseDown event which would call your "button" procedure function in place of my "beep" command. Test this by executing Panel0() from the command line.
First of all, thank you both for your comments and suggestions.
John: yes indeed it is a dynamic drawing which can get redrawn (basically part of its color changes) at different times. Clearly if the buttons are drawn on top I will need to use a custom control for this. Could I ask you for a minimal working example? I could not understand from the help file how I can draw at runtime a custom drawing "inside" a custom control.

Thanks for your kind help.

Regards,
Gregor
The example you seek is the example S.R. Chinn posted.

--Jim Prouty
Software Engineer, WaveMetrics, Inc.
There is also an example under File->Example Experiments->Feature Demos 2->Custom Control Demo. It includes a meter with a face drawn from a ProcPicture, but with the needle drawn dynamically.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
This may not be of much help, but I have had a play with using transparent custom controls and drawing things where the control is located.
The following is an example of my code to illustrate this:
#pragma rtGlobals=3     // Use modern global access method and strict wave access.
Function DemoTransparentCustomControl()
    NewPanel /W=(150,50,350,200)
    CustomControl cctb,pos={50,50},size={100,50}
    CustomControl cctb,frame=0,proc=cctButtonProc

    SetDrawLayer ProgBack
    SetDrawEnv gstart,gname=cctbDraw
    SetDrawEnv linethick=2,linefgc=(65535,0,0),rounding=10
    DrawRRect 49,49,151,101
    DrawOval 70,60,130,90
    SetDrawEnv gstop
End

Function cctButtonProc(s)
    STRUCT WMCustomControlAction &s
    s.blockReentry=1
    switch(s.eventCode)
        case 2: // mouse up
             // code for button press here
            print "Button Pressed"
            break
    endSwitch
    return 0
End


In playing with this I have found some weird behaviour - if you change the coordinates of the rounded rectangle to the following: "DrawRRect 50,50,150,100" the custom control interferes with the picture in that its rectangle is not drawn on any more. I am using Igor 6.30Beta03 on a PC running Windows 7. Has anyone got any ideas about this?

Best regards,
Kurt
Rather than trying to combine drawing elements with controls in a nonstandard way, try doing this the "standard" way: Draw the control in the CustomControl's "draw" event.

I offer this simple example:

Function DemoCustomControl()
    NewPanel /W=(150,50,350,200)
    CustomControl cctb,pos={50,50},size={100,50}
    CustomControl cctb,frame=0,proc=cctButtonProc
End
 
Function cctButtonProc(s)
    STRUCT WMCustomControlAction &s
    s.blockReentry=1
    switch(s.eventCode)
        case 10: // draw: (0,0) is top-left corner of drawn content
            Variable isHot = NumVarOrDefault("root:buttonHot",0)
            Variable right= s.ctrlRect.right-s.ctrlRect.left
            Variable bottom= s.ctrlRect.bottom-s.ctrlRect.top
            SetDrawEnv linethick=2,linefgc=(isHot ? 65535 : 0,0,0),rounding=10
            Variable mouseIsDown= s.eventmod & 0x1
            if( isHot && mouseIsDown )
                SetDrawEnv fillfgc=(0,0,0)
            endif
            DrawRRect 0,0,right,bottom
            DrawOval 20,10,right-20,bottom-10
            SetDrawEnv textxjust=1, textyjust=1 // centered at x0, y0
            DrawText right/2, bottom/2, "Custom"
            break
        case 2: // mouse up in control
             // code for button press here
            print "Button Pressed"
            break
        case 5: // Mouse entered control
            variable/G root:buttonHot= 1
            s.needAction = 1
            break;
        case 6: // Mouse left control
            variable/G root:buttonHot= 0
            s.needAction = 1
            break;
    endSwitch
    return 0
End

--Jim Prouty
Software Engineer, WaveMetrics, Inc.
CustomControl.png