Draw Rectangle or Ellipse on Desktop

Share your advanced PureBasic knowledge/code with the community.
User avatar
ChrisR
Addict
Addict
Posts: 1466
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Draw Rectangle or Ellipse on Desktop

Post by ChrisR »

As the title, Draw a Rectangle or an Ellipse on Desktop, Area Requester for Windows only

Code: Select all

;- Top
; -----------------------------------------------------------------------------
;           Name: DrawRectEllipseOnDesktop.pb
;    Description: Draw a Rectangle or an Ellipse on Desktop (Use Esc or Right Click to exit), Area Requester. 
;         Author: ChrisR
;           Date: 2022-12-29
;             OS: Windows Only, DPIaware
;           Note: For the test here, the rectangle is drawn first and then on closing the ellipse is drawn (Look for "TEST" label) 
; -----------------------------------------------------------------------------

EnableExplicit

Enumeration Window
  #WinDesktop
EndEnumeration

Enumeration Image
  #ImgDesktop
EndEnumeration

Enumeration Shortcut
  #Shortcut_Escape = 3
EndEnumeration

Global MaxW, MaxH
Global Dim Handle.Rect(5)
Global HSize = DesktopScaledX(16)   ; Image Handle Size 16,12,...
Global Ellipse                      ; DrawRectangle -> Ellipse=#False, DrawEllipse -> Ellipse=#True 

Macro InitSize()
  Handle(0)\left = MaxW /4 : Handle(0)\top = MaxH /4 : Handle(0)\right = MaxW * 3/4 : Handle(0)\bottom = MaxH * 3/4
EndMacro

Macro DrawHandle()
  ImgRect = CreateImage(#PB_Any, HSize, HSize, 32, RGBA(0,0,25,255))
  ImgRectID = ImageID(ImgRect)
  If StartDrawing(ImageOutput(ImgRect))   ; For Background Transparency
    DrawingMode(#PB_2DDrawing_AlphaChannel)
    Box(2, 2, HSize-4, HSize-4, RGBA(0,0,0,1))
    StopDrawing()
  EndIf
EndMacro

Procedure GetDesktopSize()
  Protected WinTemp.i
  WinTemp = OpenWindow(#PB_Any, 0, 0, 1, 1, "", #PB_Window_Invisible | #PB_Window_BorderLess | #PB_Window_Maximize)
  MaxW    = DesktopScaledX(WindowWidth(WinTemp))
  MaxH    = DesktopScaledY(WindowHeight(WinTemp))
  CloseWindow(WinTemp)
EndProcedure

Procedure UpdateLayeredWindow(hDC)
  Protected sz.SIZE, BlendMode.BLENDFUNCTION, ContextOffset.POINT
  ; hDC = StartDrawing(ImageOutput(#ImgDesktop))   ; Already done in DrawRectangle()
  With sz.SIZE
    \cx = ImageWidth(#ImgDesktop)
    \cy = ImageHeight(#ImgDesktop)
  EndWith
  With BlendMode.BLENDFUNCTION
    \SourceConstantAlpha = 255
    \AlphaFormat = 1
  EndWith
  UpdateLayeredWindow_(WindowID(#WinDesktop), 0, 0, @sz, hDC, @ContextOffset.POINT, 0, @BlendMode, 2)
  ; StopDrawing()   ; Already done in DrawRectangle()
EndProcedure

Procedure CalcHandlePos()
  Protected Width, Height, MHSize = HSize/2
  With Handle(0)
    Width = \right - \left : Height = \bottom - \top
    ; Handle Position
    Handle(1)\left = \left  -MHSize : Handle(1)\top = \top    -MHSize : Handle(1)\right = \left  +MHSize : Handle(1)\bottom = \top    +MHSize
    Handle(2)\left = \right -MHSize : Handle(2)\top = \top    -MHSize : Handle(2)\right = \right +MHSize : Handle(2)\bottom = \top    +MHSize
    Handle(3)\left = \right -MHSize : Handle(3)\top = \bottom -MHSize : Handle(3)\right = \right +MHSize : Handle(3)\bottom = \bottom +MHSize
    Handle(4)\left = \left  -MHSize : Handle(4)\top = \bottom -MHSize : Handle(4)\right = \left  +MHSize : Handle(4)\bottom = \bottom +MHSize
    ; Middle, center Handle
    Handle(5)\left = \Left + Width/2 -MHSize : Handle(5)\top = \top + Height/2 -MHSize : Handle(5)\right = \Left + Width/2 +MHSize  : Handle(5)\bottom = \top + Height/2 +MHSize
  EndWith  
EndProcedure

Procedure DrawEllipse()
  Protected hDC, ImgRect, RadiusX, RadiusY, I 
  Static ImgRectID
  Ellipse = #True
  
  If Not ImgRectID : DrawHandle() : EndIf
  
  CalcHandlePos()
  RadiusX = (Handle(0)\right - Handle(0)\left)/2 : RadiusY = (Handle(0)\bottom - Handle(0)\top)/2
  CreateImage(#ImgDesktop, MaxW, MaxH, 32, #PB_Image_Transparent)
  hDC = StartDrawing(ImageOutput(#ImgDesktop))
  If hDC
    DrawingMode(#PB_2DDrawing_Outlined | #PB_2DDrawing_AllChannels)
    Ellipse(Handle(0)\left + RadiusX, Handle(0)\top + RadiusY, Abs(RadiusX), Abs(RadiusY), RGBA(0,0,25,255))
    DrawingMode(#PB_2DDrawing_AllChannels)
    For I = 1 To 5
      DrawImage(ImgRectID, Handle(I)\left, Handle(I)\top)
    Next
    UpdateLayeredWindow(hDC)
    StopDrawing()
  EndIf
EndProcedure

Procedure DrawRectangle()
  Protected hDC, ImgRect, I 
  Static ImgRectID
  Ellipse = #False
  
  If Not ImgRectID : DrawHandle() : EndIf
  
  CalcHandlePos()
  CreateImage(#ImgDesktop, MaxW, MaxH, 32, #PB_Image_Transparent)
  hDC = StartDrawing(ImageOutput(#ImgDesktop))
  If hDC
    DrawingMode(#PB_2DDrawing_Outlined | #PB_2DDrawing_AllChannels)
    Box(Handle(0)\left, Handle(0)\top, Handle(0)\right - Handle(0)\left, Handle(0)\bottom - Handle(0)\top, RGBA(0,0,25,255))
    DrawingMode(#PB_2DDrawing_AllChannels)
    For I = 1 To 5
      DrawImage(ImgRectID, Handle(I)\left, Handle(I)\top)
    Next
    UpdateLayeredWindow(hDC)
    StopDrawing()
  EndIf
EndProcedure

;- Main
Define EventID, Drag, MouseX, MouseX0, MouseY, MouseY0, DragX, DragY, ID

GetDesktopSize()
OpenWindow(#WinDesktop, 0, 0, MaxW, MaxH, "", #PB_Window_BorderLess | #PB_Window_ScreenCentered)
SetWindowLongPtr_(WindowID(#WinDesktop), #GWL_EXSTYLE, GetWindowLongPtr_(WindowID(#WinDesktop), #GWL_EXSTYLE) | #WS_EX_LAYERED)
StickyWindow(#WinDesktop, #True)

CreatePopupMenu(0)
MenuItem(#Shortcut_Escape, "Exit")
AddKeyboardShortcut(#WinDesktop, #PB_Shortcut_Escape, #Shortcut_Escape)

InitSize()
DrawRectangle()
;DrawEllipse()

Repeat
  If Drag
    If Not (GetKeyState_(#VK_LBUTTON) & 32768)
      Drag = #False
    EndIf
    MouseX = DesktopMouseX()
    MouseY = DesktopMouseY()
    If MouseX <> MouseX0 Or MouseY <> MouseY0
      DragX   = MouseX - MouseX0 : DragY = MouseY - MouseY0
      MouseX0 = MouseX           : MouseY0 = MouseY
      With Handle(0)
        Select ID
          Case 1
            \left   + DragX : \top    + DragY
          Case 2
            \top    + DragY : \right  + DragX
          Case 3
            \right  + DragX : \bottom + DragY
          Case 4
            \left   + DragX : \bottom + DragY
          Case 5  ; Move
            If \left + DragX >= 0 And \left + DragX <= MaxW And \right  + DragX >= 0 And \right  + DragX <= MaxW
              \left + DragX : \right  + DragX
            EndIf
            If \top  + DragY >= 0 And \top  + DragY <= MaxH And \bottom + DragY >= 0 And \bottom + DragY <= MaxH
              \top  + DragY : \bottom + DragY
            EndIf
        EndSelect
      EndWith
      If Ellipse
        DrawEllipse()
      Else
        DrawRectangle()
      EndIf
    EndIf
  EndIf
  
  EventID = WaitWindowEvent(1)
  Select EventID
    Case #WM_LBUTTONDOWN
      MouseX0 = DesktopMouseX()
      MouseY0 = DesktopMouseY()
      For ID = 1 To 5
        If MouseX0 >= Handle(ID)\left And MouseY0 >= Handle(ID)\top And MouseX0 <= Handle(ID)\right And MouseY0 <= Handle(ID)\bottom
          Drag = #True
          Break
        EndIf
      Next
      ;SendMessage_(WindowID(#WinDesktop), #WM_NCLBUTTONDOWN, #HTCAPTION, 0)   ; Move the image by following mouse movements 
      
    Case #WM_LBUTTONUP
      Drag = #False
      
    Case #PB_Event_Menu
      If EventMenu() = #Shortcut_Escape
        With Handle(0)
          Debug "Left: " + Str(\left) + " - Top: " + Str(\top) + " - Right: " + Str(\right) + " - Bottom: " + Str(\bottom) + " - (Play with Min, Max if needed)" 
        EndWith
        ; TEST: Draw Rectangle then Ellipse. Not to do, remove the If-Endif block and replace it by Break only
        If Ellipse = #False   
          InitSize()
          DrawEllipse()
        Else
          Break
        EndIf
      EndIf
      
    Case #WM_RBUTTONDOWN
      DisplayPopupMenu(0, WindowID(#WinDesktop))
      
  EndSelect
Until EventID = #PB_Event_CloseWindow
Axolotl
Addict
Addict
Posts: 838
Joined: Wed Dec 31, 2008 3:36 pm

Re: Draw Rectangle or Ellipse on Desktop

Post by Axolotl »

Thank you for sharing.
This is very nice, unfortunately I have no use for it so far.
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
Post Reply