Moving a borderless window ?

Just starting out? Need help? Post your questions and find answers here.
Joubarbe
Enthusiast
Enthusiast
Posts: 555
Joined: Wed Sep 18, 2013 11:54 am
Location: France

Moving a borderless window ?

Post by Joubarbe »

Hi,

I'm not really sure whether I have to use the Drag&Drop library or not to move a #PB_Window_BorderLess window. It seems that it's only made for dragging files, images and texts inside or outside a window or a gadget. But I'm searching for an event that recognize that the left click is pressed and hold, then I'll use ResizeWindow() to move my window at DesktopMouseX(), DesktopMouseY(). An ideal solution would be to have a specific area that accepts this kind of event.

So, if you can help, you'll receive all my gratitude :) ...
User avatar
Danilo
Addict
Addict
Posts: 3037
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: Moving a borderless window ?

Post by Danilo »

Code: Select all

If OpenWindow(0, 0, 0, 800, 600, "Moveable window", #PB_Window_BorderLess | #PB_Window_ScreenCentered)
    ButtonGadget(0,10,10,100,25,"Exit")
    CocoaMessage(0, WindowID(0), "setMovableByWindowBackground:", #YES) ; make window moveable by mouse
  
    Repeat
        Select WaitWindowEvent()
            Case #PB_Event_CloseWindow : End
            Case #PB_Event_Gadget
                If EventGadget()=0 And EventType()=#PB_EventType_LeftClick
                    End
                EndIf
        EndSelect
    ForEver
EndIf
User avatar
Danilo
Addict
Addict
Posts: 3037
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: Moving a borderless window ?

Post by Danilo »

Joubarbe wrote:But I'm searching for an event that recognize that the left click is pressed and hold, then I'll use ResizeWindow() to move my window at DesktopMouseX(), DesktopMouseY(). An ideal solution would be to have a specific area that accepts this kind of event.
For the specific area, you could use an Canvasgadget().

Code: Select all

Procedure Exit()
    End
EndProcedure

Procedure LeftMouseDown()
    Shared MouseDown, OffsetX, OffsetY
    MouseDown = #True
    offsetX = WindowMouseX(0)
    OffsetY = WindowMouseY(0)
EndProcedure

Procedure LeftMouseUp()
    Shared MouseDown
    MouseDown = #False
EndProcedure

Procedure MouseMove()
    Shared MouseDown, OffsetX, OffsetY
    If MouseDown And GetGadgetAttribute(1,#PB_Canvas_Buttons)&#PB_Canvas_LeftButton
        ResizeWindow(0,DesktopMouseX()-OffsetX,DesktopMouseY()-OffsetY,#PB_Ignore,#PB_Ignore)
    EndIf
EndProcedure

If OpenWindow(0, 0, 0, 800, 600, "Moveable window", #PB_Window_BorderLess | #PB_Window_ScreenCentered)
    ButtonGadget(0,10,10,100,25,"Exit")
    BindEvent(#PB_Event_Gadget,@Exit(),0,0,#PB_EventType_LeftClick)
    
    CanvasGadget(1,120,10,200,200)
    BindEvent(#PB_Event_Gadget,@LeftMouseDown(),0,1,#PB_EventType_LeftButtonDown)
    BindEvent(#PB_Event_Gadget,@LeftMouseUp()  ,0,1,#PB_EventType_LeftButtonUp)
    BindEvent(#PB_Event_Gadget,@MouseMove()    ,0,1,#PB_EventType_MouseMove)
    
    If StartDrawing(CanvasOutput(1))
        Box(0,0,OutputWidth(),OutputHeight(),RGB(0,0,128))
        StopDrawing()
    EndIf
    
    Repeat:WaitWindowEvent():ForEver
EndIf
Joubarbe
Enthusiast
Enthusiast
Posts: 555
Joined: Wed Sep 18, 2013 11:54 am
Location: France

Re: Moving a borderless window ?

Post by Joubarbe »

You win the achievement #AllMyGratitude. You can't share it with friends.

(Thanks!)
User avatar
TI-994A
Addict
Addict
Posts: 2512
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: Moving a borderless window ?

Post by TI-994A »

Hi Danilo; great code, as always. I've noticed that there doesn't seem to be any OSX examples on the forum that demonstrate such moving by dragging only designated areas of the window. This example illustrates how to handle such moves for both Windows and OSX:

Code: Select all

;==================================================
;
;   Moving a window by clicking on the background
;         or on any designated part of it       
;
;              for Windows and OSX       
;
;        by TI-994A  -  26th October 2013      
;
;==================================================

EnableExplicit

#NSMouseMoved = 5

Enumeration
  #MainWindow
  #Button1
  #Button2
EndEnumeration

CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
  Structure RECT
    left.i
    top.i
    right.i
    bottom.i
  EndStructure
CompilerEndIf

Define appQuit, xDraw, useHotspot, hotSpot.RECT, stateText.s

With hotSpot
  \left = 0
  \right = 400
  \top = 30
  \bottom = 70
EndWith

Procedure inHotSpot(*hotSpot.RECT)
  Define result
  With *hotSpot
    If WindowMouseX(#MainWindow) > \left And
       WindowMouseX(#MainWindow) < \right And
       WindowMouseY(#MainWindow) > \top And
       WindowMouseY(#MainWindow) < \bottom
      result = 1
    EndIf
  EndWith
  ProcedureReturn result
EndProcedure

Macro drawTitle()
  StartDrawing(WindowOutput(#MainWindow))
  Box(hotSpot\left, hotSpot\top, hotSpot\right - hotSpot\left,
      hotSpot\bottom - hotSpot\top, RGB(0, 0, 150))
    xDraw = (400 - TextWidth(stateText)) / 2
    DrawText(xDraw, 40, stateText, RGB(255, 255, 255), RGB(0, 0, 150))
  StopDrawing()
EndMacro

Macro moveMode()
  If useHotspot
    useHotspot = 0
    SetGadgetText(#Button1, "change to specific area")
    stateText = "click anywhere on this window to move it"
    drawTitle()
    CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
      CocoaMessage(0, WindowID(#MainWindow), "setMovableByWindowBackground:", #YES)
    CompilerEndIf
  Else
    useHotspot = 1
    SetGadgetText(#Button1, "change to full window")
    stateText = "click anywhere on this bar to move the window"
    drawTitle()
  EndIf
EndMacro

OpenWindow(#MainWindow, 0, 0, 400, 300, "Move Borderless Window", 
           #PB_Window_BorderLess | #PB_Window_ScreenCentered)
ButtonGadget(#Button1, 10, 260, 180, 30, "change to specific area")  
ButtonGadget(#Button2, 210, 260, 180, 30, "q u i t")
SetWindowColor(#MainWindow, RGB(150, 150, 250))


CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
  Define cocoaEvent, cocoaEventType
  Define sharedApp = CocoaMessage(0, 0, "NSApplication sharedApplication")
  CocoaMessage(0, WindowID(#MainWindow), "setMovableByWindowBackground:", #YES)
  CocoaMessage(0, WindowID(#MainWindow), "setAcceptsMouseMovedEvents:", #YES)
  MessageRequester("Borderless Window", "moving a window without a title bar")
CompilerEndIf

stateText = "click anywhere on this window to move it"
drawTitle()

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_Gadget
      Select EventGadget()
        Case #Button1
          moveMode()
        Case #Button2
          appQuit = 1
      EndSelect
      
      CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      Case #WM_PAINT
        drawTitle()
      Case #WM_LBUTTONDOWN
        If (useHotspot And inHotSpot(@hotSpot)) Or Not useHotspot
          SendMessage_(WindowID(#MainWindow), #WM_NCLBUTTONDOWN, #HTCAPTION, 0)
        EndIf
      CompilerEndIf
      
  EndSelect
  
  CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
    cocoaEvent = CocoaMessage(0, sharedApp, "currentEvent")
    If cocoaEvent
      cocoaEventType = CocoaMessage(0, cocoaEvent, "type")
      If cocoaEventType = #NSMouseMoved And useHotspot
        If inHotSpot(@hotSpot)
          CocoaMessage(0, WindowID(#MainWindow),
                       "setMovableByWindowBackground:", #YES)
        Else
          CocoaMessage(0, WindowID(#MainWindow),
                       "setMovableByWindowBackground:", #NO)
        EndIf
      EndIf
    EndIf    
  CompilerEndIf        
  
Until appQuit
The mechanics of the mouse events itself is quite short, and the rest is just the demonstration code. :)
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
User avatar
Danilo
Addict
Addict
Posts: 3037
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: Moving a borderless window ?

Post by Danilo »

Thanks TI-994A, nice code.
User avatar
BasicallyPure
Enthusiast
Enthusiast
Posts: 536
Joined: Thu Mar 24, 2011 12:40 am
Location: Iowa, USA

Re: Moving a borderless window ?

Post by BasicallyPure »

I have been trying to do this with a different variation.
I would like to be able to drag the window only if the user clicks on the window background.
Any clicks on gadgets should be ignored.
Is there some clever API trick that will detect a click only on the window background?

This code almost works but not totally.
Right click to exit.

BP

edit: thanks to Danilo's help it now works as desired.

Code: Select all

EnableExplicit

#MainWin   = 0
#PopUpMenu = 0
#Canvas = 0
#StrGad = 1
#ButtonGad = 2
#MenuChoice_OnTop = 0
#MenuChoice_Quit  = 1

Declare INIT_GUI()
Declare EVENT_LOOP()
Declare WinCallback(hWnd, msg, wParam, lParam)

If INIT_GUI()
   EVENT_LOOP()
EndIf

End

; procedures
Procedure EVENT_LOOP()
   Protected.i TopState, Quit
   
   Repeat
      Select WaitWindowEvent()
         Case #PB_Event_RightClick
            DisplayPopupMenu(#PopUpMenu, WindowID(#MainWin))
         Case #PB_Event_Menu
            Select EventMenu()
               Case #MenuChoice_OnTop : TopState ! 1
                  StickyWindow(#MainWin, TopState)
                  SetMenuItemState(#PopUpMenu, #MenuChoice_OnTop, TopState)
               Case #MenuChoice_Quit : Quit = #True
            EndSelect
         Case #PB_Event_Gadget
            Select EventGadget()
               Case #Canvas
                  ;Debug EventType()
               Case #StrGad
                  ;Debug EventType()
               Case #ButtonGad
                  ;Debug EventType()
            EndSelect
         Case #PB_Event_CloseWindow : Quit = #True
      EndSelect
      Until Quit
   EndProcedure
   
Procedure INIT_GUI()
   ; returns window handle on success or 0 if fail.
   Protected flags.i  = #PB_Window_ScreenCentered | #PB_Window_BorderLess
   Protected Result.i = OpenWindow(#MainWin, 0, 0, 344, 54, "Drag Borderless Window", flags)
   
   If Result
      SetWindowCallback(@WinCallback())
      
      If CreatePopupMenu(#PopUpMenu)
         MenuItem(#MenuChoice_OnTop, "Always on top")
         MenuItem(#MenuChoice_Quit,"Quit")
      Else : Result = 0
      EndIf
      
      If CanvasGadget(#Canvas,80,10,150,35)
         StartDrawing(CanvasOutput(#Canvas))
            Box(0,0,150,35,$650015)
            DrawText(10,10,"Canvas",$FFFFFF,$650015)
         StopDrawing()
      Else : Result = 0
      EndIf
      
      If StringGadget(#StrGad,15,15,50,25,"string") And
         ButtonGadget(#ButtonGad,250,10,70,30,"Button")
      Else : Result = 0
      EndIf
      
   EndIf
   
   ProcedureReturn Result
EndProcedure

Procedure WinCallback(hWnd, msg, wParam, lParam)
    If msg = #WM_LBUTTONDOWN
        SendMessage_(hWnd, #WM_NCLBUTTONDOWN, #HTCAPTION, 0)
        ProcedureReturn 0
    EndIf 
    
    ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure
Last edited by BasicallyPure on Sun Oct 27, 2013 4:05 am, edited 1 time in total.
BasicallyPure
Until you know everything you know nothing, all you have is what you believe.
User avatar
Danilo
Addict
Addict
Posts: 3037
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: Moving a borderless window ?

Post by Danilo »

BasicallyPure wrote:I have been trying to do this with a different variation.
I would like to be able to drag the window only if the user clicks on the window background.
Any clicks on gadgets should be ignored.
Is there some clever API trick that will detect a click only on the window background?
Just use a window callback and remove the WinAPI mouse messages from your event loop.

Code: Select all

Procedure WinCallback(hWnd, msg, wParam, lParam)    
    If msg = #WM_LBUTTONDOWN
        SendMessage_(hWnd, #WM_NCLBUTTONDOWN, #HTCAPTION, 0)
        ProcedureReturn 0
    EndIf 
    
    ProcedureReturn #PB_ProcessPureBasicEvents 
EndProcedure 

SetWindowCallback(@WinCallback())
User avatar
BasicallyPure
Enthusiast
Enthusiast
Posts: 536
Joined: Thu Mar 24, 2011 12:40 am
Location: Iowa, USA

Re: Moving a borderless window ?

Post by BasicallyPure »

Thanks Danilo, that's exactly what I wanted.
I have updated my code above.
I see that you used the same SendMessage_ that TI-994A used in his example.

Code: Select all

SendMessage_(WindowID(#MainWindow), #WM_NCLBUTTONDOWN, #HTCAPTION, 0)
I don't understand why it works but I cannot deny that it does.

BP
BasicallyPure
Until you know everything you know nothing, all you have is what you believe.
User avatar
Danilo
Addict
Addict
Posts: 3037
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: Moving a borderless window ?

Post by Danilo »

BasicallyPure wrote:I see that you used the same SendMessage_ that TI-994A used in his example.
Check out 10 years old CodeArchive: CodeArchiv_v393/Windows/FX/Move_borderless_Window.pb ;)

It is recommended to do it in a callback now, but many of the old PB tricks in the CodeArchive still work,
at least with slightly adjustments. Check out the (old & new) CodeArchive at http://purearea.net
BasicallyPure wrote:

Code: Select all

SendMessage_(WindowID(#MainWindow), #WM_NCLBUTTONDOWN, #HTCAPTION, 0)
I don't understand why it works but I cannot deny that it does.
It tells Windows that the left mouse button is down on the non-client area of the window, specifically on the title bar (caption),
so Windows switches to a special "move window" mode.
User avatar
Michael Vogel
Addict
Addict
Posts: 2666
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Moving a borderless window ?

Post by Michael Vogel »

Would it also be possible to move the window by clicking on a CanvasGadget?

Code: Select all

Enumeration
	#MainWindow
	#MenuQuit
EndEnumeration

WinID=OpenWindow(#MainWindow,0,0,500,500,"", #PB_Window_ScreenCentered|#PB_Window_BorderLess|#PB_Window_Invisible)
SetWindowColor(#MainWindow,#Red)
CanvasGadget(0,0,0,500,500);   <------
AddKeyboardShortcut(#MainWindow,#PB_Shortcut_Escape,#MenuQuit)

StickyWindow(#MainWindow,1)
HideWindow(#MainWindow,0)

Repeat
	Select WaitWindowEvent()

	Case #PB_Event_CloseWindow
		Break

	Case #PB_Event_Menu
		If EventGadget()=#MenuQuit
			Break
		EndIf

	Case #WM_LBUTTONDOWN
		Debug "down"
		SendMessage_(WinID,#WM_NCLBUTTONDOWN,#HTCAPTION,0)
		Debug "ok"

	EndSelect
ForEver

User avatar
TI-994A
Addict
Addict
Posts: 2512
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: Moving a borderless window ?

Post by TI-994A »

Michael Vogel wrote:Would it also be possible to move the window by clicking on a CanvasGadget?
Sure:

Code: Select all

Enumeration
  #MainWindow
  #Canvas
EndEnumeration

wFlags = #PB_Window_ScreenCentered | #PB_Window_BorderLess
OpenWindow(#MainWindow, #PB_Any, #PB_Any, 500, 500, "", wFlags)
CanvasGadget(#Canvas, 5, 5, 490, 490)
SetWindowColor(#MainWindow, #Red)

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_Gadget
      Select EventGadget()
        Case #Canvas
          Select EventType()
            Case #PB_EventType_LeftButtonDown
              DisableGadget(#Canvas, 1)
              SendMessage_(WindowID(#MainWindow), #WM_NCLBUTTONDOWN, #HTCAPTION, 0)
              DisableGadget(#Canvas, 0)
          EndSelect
      EndSelect
  EndSelect
ForEver
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4637
Joined: Sun Apr 12, 2009 6:27 am

Re: Moving a borderless window ?

Post by RASHAD »

Hi MV
With CanvasGadget() or any control else
See what Danilo did with moving by area
Or :

Code: Select all


WinID=OpenWindow(#MainWindow,0,0,500,500,"", #PB_Window_ScreenCentered|#PB_Window_BorderLess|#PB_Window_Invisible)
SetWindowColor(#MainWindow,#Red)
CanvasGadget(0,0,0,500,500);   <------
AddKeyboardShortcut(#MainWindow,#PB_Shortcut_Escape,#MenuQuit)

StickyWindow(#MainWindow,1)
HideWindow(#MainWindow,0)

Repeat
   Select WaitWindowEvent()

   Case #PB_Event_CloseWindow
      Break

   Case #PB_Event_Menu
      If EventGadget()=#MenuQuit
         Break
      EndIf
      
   Case #WM_MOUSEMOVE
        GetCursorPos_(m.POINT)
        ScreenToClient_(WindowID(#MainWindow),m)
        If Down = 1
           ResizeWindow(#MainWindow,WindowX(#MainWindow)+m\x-p\x,WindowY(#MainWindow)+m\y-p\y,#PB_Ignore,#PB_Ignore)
        EndIf

   Case #WM_LBUTTONDOWN
        GetCursorPos_(p.POINT)
        ScreenToClient_(WindowID(#MainWindow),p)
        Down = 1
        
   Case #WM_LBUTTONUP
        Down = 0

   EndSelect
ForEver
Egypt my love
User avatar
Michael Vogel
Addict
Addict
Posts: 2666
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Moving a borderless window ?

Post by Michael Vogel »

Thanks to you both, you are brilliant!

But... :wink:

... how to keep #PB_EventType_LeftClick events working? These seems to be impossible in both cases. I tried to add a SetActiveGadget(#Canvas) line after enabling the gadget in TI-99s code, but with no success.

And I tried to modify Rashads code to check if the button down and up events have been done at the same cursor position, but in all cases "down" is set to 0 after releasing the mouse button...

Code: Select all

		Case #WM_MOUSEMOVE
			;Case #PB_EventType_MouseMove
			GetCursorPos_(m.POINT)
			ScreenToClient_(WinApps,m)
			If Down=1
				ResizeWindow(#WinApps,WindowX(#WinApps)+m\x-p\x,WindowY(#WinApps)+m\y-p\y,#PB_Ignore,#PB_Ignore)
				Debug "M"
			EndIf
		Case #WM_LBUTTONDOWN
			;Case #PB_EventType_LeftButtonDown
			Debug "*"
			GetCursorPos_(p.POINT)
			ScreenToClient_(WinApps,p)
			Down=1
			Debug "D"
		Case #WM_LBUTTONUP
			;Case #PB_EventType_LeftButtonUp
			Debug "U"
			If m\x=p\x And m\y=p\y
				Debug "0"
				Down=0
			Else
				Debug "+"
				Down=2
			EndIf
		:
		:
			Case #PB_EventType_LeftClick
				If Down=0
			:

RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4637
Joined: Sun Apr 12, 2009 6:27 am

Re: Moving a borderless window ?

Post by RASHAD »

Ctrl down to move around
Ctrl up to Normal case

Remember it does not matter if the CanvasGadget() is the Z-Order object or not

Code: Select all

Enumeration
   #MainWindow
   #MenuQuit
EndEnumeration
Define p.POINT,m.POINT

WinID=OpenWindow(#MainWindow,0,0,500,500,"", #PB_Window_ScreenCentered|#PB_Window_BorderLess|#PB_Window_Invisible)
SetWindowColor(#MainWindow,#Red)
CanvasGadget(0,0,0,500,500);   <------
AddKeyboardShortcut(#MainWindow,#PB_Shortcut_Escape,#MenuQuit)

StickyWindow(#MainWindow,1)
HideWindow(#MainWindow,0)

Repeat
   Select WaitWindowEvent()

   Case #PB_Event_CloseWindow
      Break

   Case #PB_Event_Menu
      If EventGadget()=#MenuQuit
         Break
      EndIf
      
   Case #PB_Event_Gadget
      Select EventGadget()
        Case 0
            If EventType() = #PB_EventType_LeftButtonDown Or (EventType() = #PB_EventType_MouseMove And GetGadgetAttribute(0, #PB_Canvas_Buttons) & #PB_Canvas_LeftButton)
              If GetAsyncKeyState_(#VK_CONTROL) & 32768 = 0
                StartDrawing(CanvasOutput(0))
                x = GetGadgetAttribute(0, #PB_Canvas_MouseX)
                y = GetGadgetAttribute(0, #PB_Canvas_MouseY)
                Circle(x, y, 10, RGB(Random(255), Random(255), Random(255)))
                StopDrawing()
              EndIf
            EndIf
      EndSelect
      
   Case #WM_MOUSEMOVE
        GetCursorPos_(m.POINT)
        ScreenToClient_(WindowID(#MainWindow),m)
        If Down = 1
           ResizeWindow(#MainWindow,WindowX(#MainWindow)+m\x-p\x,WindowY(#MainWindow)+m\y-p\y,#PB_Ignore,#PB_Ignore)
        EndIf

   Case #WM_LBUTTONDOWN
        If GetAsyncKeyState_(#VK_CONTROL) & 32768 = 32768
          GetCursorPos_(p.POINT)
          ScreenToClient_(WindowID(#MainWindow),p)
          Down = 1
        Else
          Down = 0
        EndIf        

   EndSelect
ForEver
Egypt my love
Post Reply