Page 1 of 1

Elliptic CanvasGadget

Posted: Thu Jul 14, 2011 4:56 pm
by einander
As the CanvasGadget is so useful, a good complement would be EllipticCanvasGadget, with the same coordinates than the normal one, like the GdipDrawEllipse function, that takes the four corners of the bounding rectangle that the ellipse is drawn within.

Re: Elliptic CanvasGadget

Posted: Thu Jul 14, 2011 5:09 pm
by Trond
Couldn't this be solved by making the canvas gadget display with alpha? That way, just make whatever area is "outside" the control transparent.

Re: Elliptic CanvasGadget

Posted: Thu Jul 14, 2011 6:34 pm
by netmaestro
Couldn't this be solved by making the canvas gadget display with alpha?
There are a number of problems with this approach unfortunately. The gadget can't be layered as it's a child window, so it would have to be alphablended with the window background at each redraw. This is how the current ImageGadget functions, and when it contains a 32bit image it flickers a lot if it's updated too rapidly. The CanvasGadget needs to perform redraws smoothly because a lot of applications for it involve animations and so that doesn't leave too many options for making it partially transparent. One thing you can do on Windows though, is apply a region to it:

Code: Select all

OpenWindow(0,0,0,640,480,"",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)

CanvasGadget(0,20,20,400,300)

hRgn = CreateEllipticRgn_(0,0,400,300)
SetWindowRgn_(GadgetID(0), hrgn, 1)

Repeat
  EventID = WaitWindowEvent()
  Select EventID
    Case #PB_Event_Gadget
      If EventGadget()=0 And EventType()=#PB_EventType_LeftButtonDown
        Debug "Button Down!"
      EndIf
  EndSelect
Until EventID = #PB_Event_CloseWindow
It won't accept any events outside its region. Only drawback here is that you can't antialias the ellipse.

Re: Elliptic CanvasGadget

Posted: Thu Jul 14, 2011 7:04 pm
by einander
Thanks Trond and Netmaestro. :)
I still think that a native multiplatform Elliptic Canvas could be useful.

I don't need this now; don't take it as coding question but only as an idea that Fred or Freak may or not consider interesting.

(As long as I remember, this is my first request in 8 years. :shock: )
Cheers!

Re: Elliptic CanvasGadget

Posted: Thu Jul 14, 2011 7:48 pm
by Trond
netmaestro wrote:
Couldn't this be solved by making the canvas gadget display with alpha?
...
This is how the current ImageGadget functions, and when it contains a 32bit image it flickers a lot if it's updated too rapidly.
Just because it's currently implemented with flicker, doesn't mean it has to be implemented that way.

Code: Select all

Global OldProc
Global BackBuffer = CreateImage(#PB_Any, 512, 512, 24)

; Procedure Blend(source, target)
;   R = Red(source)
;   B = Blue(source)
;   G = Green(source)
;   
;   R2 = Red(target)
;   B2 = Blue(target)
;   G2 = Green(target)
;   
;   Alpha = Alpha(source)
;   
;   R = ((R*Alpha)/255) + ((R2*(255-Alpha)) / 255)
;   G = ((G*Alpha)/255) + ((G2*(255-Alpha)) / 255)
;   B = ((B*Alpha)/255) + ((B2*(255-Alpha)) / 255)
;   
;   ProcedureReturn RGB(R, G, B)
; EndProcedure

Procedure Callback(WindowID, Message, wParam, lParam)
  Protected Result = #PB_ProcessPureBasicEvents
  
  Select Message
    Case #WM_ERASEBKGND
      ; Debug "erase bkgnd"
      Result = 1
    Case #WM_PAINT
      hDC_b = StartDrawing(ImageOutput(BackBuffer))
        Box(0, 0, 512, 512, GetSysColor_(#COLOR_3DFACE))
        DrawingMode(#PB_2DDrawing_AlphaBlend)
        DrawImage(ImageID(0), 0, 0)
      
        hDC_w = BeginPaint_(WindowID, @paint.PAINTSTRUCT)
          BitBlt_(hDC_w, 0, 0, 512, 512, hDC_b, 0, 0, #SRCCOPY)
        EndPaint_(WindowID, @paint)
      StopDrawing()
      ; Alternate blend code, without backbuffer, but too slow
;       hDC_w = BeginPaint_(WindowID, @paint.PAINTSTRUCT)
;       bg = GetSysColor_(#COLOR_3DFACE)
;       hDC_i = StartDrawing(ImageOutput(0))
;       DrawingMode(#PB_2DDrawing_AllChannels)
;         For x = 0 To 511
;           For y = 0 To 511
;             color = Blend(Point(x, y), bg)
;             SetPixel_(hDC_w, x, y, color)
;           Next
;         Next
;       StopDrawing()
;       EndPaint_(WindowID, @paint)
      Result = 0
  EndSelect
  
  If Result = #PB_ProcessPureBasicEvents
    ProcedureReturn CallWindowProc_(OldProc, WindowID, Message, wParam, lParam)
  Else
    ProcedureReturn Result
  EndIf
EndProcedure



CreateImage(0, 512, 512, 32)


Procedure RotateImage()
  Static Angle.d = 0
  Angle + 0.5
  Angle = Mod(Angle, 360)
  
  StartDrawing(ImageOutput(0))
    DrawingMode(#PB_2DDrawing_AllChannels | #PB_2DDrawing_Gradient)
    GradientColor(0, RGBA(192, 128, 0, 255))
    GradientColor(1, RGBA(192, 128, 0, 0))
    ConicalGradient(256, 256, Angle)
    
    Box(0, 0, 512, 512)
  StopDrawing()
EndProcedure

#W = 600
#H = 600

OpenWindow(0, 0, 0, #W, #H, "", #PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
ImageGadget(0, 0, 0, 0, 0, ImageID(0))
AddWindowTimer(0, 0, 30)
SmartWindowRefresh(0, 1) ; !!

hwnd = GadgetID(0)
OldProc = SetWindowLongPtr_(hwnd, #GWLP_WNDPROC, @Callback())

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_Timer
      RotateImage()
      SetGadgetState(0, ImageID(0))
      t2 = ElapsedMilliseconds()-t
    Case #PB_Event_CloseWindow
      Break
  EndSelect
ForEver


Re: Elliptic CanvasGadget

Posted: Fri Jul 15, 2011 1:27 am
by netmaestro
It's not that simple. You have to alphablend with the actual background, not just the solid color you expect it to be. A premultiplication is necessary followed by AlphaBlend_() with the background DC at each redraw. I trust that the PB implementation is performing about as well as is possible given the task and constraints.

Re: Elliptic CanvasGadget

Posted: Fri Jul 15, 2011 8:45 am
by Trond
You have to alphablend with the actual background, not just the solid color you expect it to be.
I thought, that since PB manages both the window and the gadget, the gadget implementation could know which background brush or color was used on the window. Of course, this wouldn't work if the user painted the window background in a callback, but mixing API and PB were never guaranteed anyways.
Note that there is no "actual background", as SmartWindowRefresh() is on, causing the background paint of the window to not go where there are controls. The background must always be drawn by the gadget anyways in this case, and currently it doesn't work at all.
I agree it's not a 100% true solution, but I believe that when implemented correctly (without such assumptions as I made) it will work for 99% of users.