Page 1 of 1

Painting on an imagegadget with the mouse using Plot()

Posted: Fri Apr 11, 2008 2:22 pm
by Hydrate
Im trying to paint on an imagegadget (by painting to the image) using the plot command with the mouse. My problem is that even if I put this command in the Callback, or the eventloop of my program when I move the mouse too quickly it misses bits. This suggests to me that the program is not picking up the mouse moving as fast as it is, how can I do this?

The basic function is if LeftMouseDown them a variable is set to true, if that is true it draws.. Then if LeftMouseUp its set to false again.

Any ideas?

Posted: Fri Apr 11, 2008 2:29 pm
by Trond
Use a line instead of a point.

Posted: Fri Apr 11, 2008 2:37 pm
by srod
Try capturing the mouse input as soon as the button is clicked. Use SetCapture_(). Don't forget to release the capture on mouse up though!

Posted: Fri Apr 11, 2008 3:56 pm
by Trond
Won't help, he needs to use lines between the last point and the current one.

Posted: Fri Apr 11, 2008 4:39 pm
by Fluid Byte
You may try this:

Code: Select all

Global lpPrevFunc

Procedure StaticProc(hWnd,uMsg,wParam,lParam)
	Static MTX,MTY
	
    Select uMsg
		Case #WM_LBUTTONDOWN
		MX = lParam & $FFFF : MY = lParam  >> 16		
		MTX = MX : MTY = MY

		StartDrawing(ImageOutput(0))
		Plot(MX,MY,#White)
		StopDrawing()
		
		Case #WM_MOUSEMOVE			
		If wParam & #MK_LBUTTON
			GetCursorPos_(cpt.POINT)			
			ScreenToClient_(hWnd,cpt)
		
			MX = cpt\x : MY = cpt\y
						
			StartDrawing(ImageOutput(0))
			LineXY(MTX,MTY,MX,MY,#White)
			StopDrawing()
			
			MTX = MX : MTY = MY
			
			SetGadgetState(0,ImageID(0))
			
			SetCapture_(hWnd)
		EndIf
		
		Case #WM_LBUTTONUP
		ReleaseCapture_()
    EndSelect
     
    ProcedureReturn CallWindowProc_(lpPrevFunc,hWnd,uMsg,wParam,lParam)
EndProcedure

CreateImage(0,300,220)
StartDrawing(ImageOutput(0))
Box(0,0,310,230,#Gray)
StopDrawing()

OpenWindow(0,0,0,320,240,"PurePaint",#PB_Window_SystemMenu | #PB_Window_ScreenCentered)
CreateGadgetList(WindowID(0))
ImageGadget(0,10,10,0,0,ImageID(0),0)

lpPrevFunc = SetWindowLong_(GadgetID(0),#GWL_WNDPROC,@StaticProc())

While WaitWindowEvent() ! #PB_Event_CloseWindow : Wend
[edit]
Some important information:

- You need to call SetCapture_() in order to still recieve the #WM_MOUSEMOVE message when moving the mouse out of the client area respectivley if it gets negative.

- You may wounder why SetCapture_() is called constantly instead just once for #WM_LBUTTONDOWN. I tested this, it doesn't work. It needs to be called constantly while moving the mouse.

- Only the Y-Coordinate recieved from #WM_MOUSEMOVE can get negative, not X-Coordinate. If it gets smaller then NULL it becomes a value of $FFFF. So I use GetCursorPos_() / ScreenToClient_() to avoid this.

Posted: Fri Apr 11, 2008 5:05 pm
by milan1612
@Fluid: I don't know why, but your example almost locks one core of my processor :?

Posted: Fri Apr 11, 2008 5:06 pm
by Fluid Byte
Oops! :oops:

Sorry mate, just replace WindowEvent() with WaitWindowEvent(). :)

Posted: Fri Apr 11, 2008 5:14 pm
by milan1612
Fluid Byte wrote:Oops! Image

Sorry mate, just replace WindowEvent() with WaitWindowEvent(). Image
Ahh, didn't see that :lol:

Posted: Fri Apr 11, 2008 6:22 pm
by Hydrate
Using lines instead works fantastically, thank you very much.

Posted: Fri Apr 11, 2008 8:21 pm
by srod
Fluid Byte wrote:- You may wounder why SetCapture_() is called constantly instead just once for #WM_LBUTTONDOWN. I tested this, it doesn't work. It needs to be called constantly while moving the mouse.
It is because of your blanket call to 'CallWindowProc_()' etc. You should really capture the mouse once only in this kind of situation :

Code: Select all

 
Global lpPrevFunc 

Procedure StaticProc(hWnd,uMsg,wParam,lParam) 
   Static MTX,MTY 
    
    Select uMsg 
      Case #WM_LBUTTONDOWN 
      MX = lParam & $FFFF : MY = lParam  >> 16       
      MTX = MX : MTY = MY 

      StartDrawing(ImageOutput(0)) 
      Plot(MX,MY,#White) 
      StopDrawing() 
      result = CallWindowProc_(lpPrevFunc,hWnd,uMsg,wParam,lParam) 
      SetCapture_(hWnd) 
       
      Case #WM_MOUSEMOVE          
      If wParam & #MK_LBUTTON 
         GetCursorPos_(cpt.POINT)          
         ScreenToClient_(hWnd,cpt) 
       
         MX = cpt\x : MY = cpt\y 
                   
         StartDrawing(ImageOutput(0)) 
         LineXY(MTX,MTY,MX,MY,#White) 
         StopDrawing() 
          
         MTX = MX : MTY = MY 
          
         SetGadgetState(0,ImageID(0)) 
      Else
        result = CallWindowProc_(lpPrevFunc,hWnd,uMsg,wParam,lParam) 
      EndIf 
       
      Case #WM_LBUTTONUP 
      ReleaseCapture_() 
      result = CallWindowProc_(lpPrevFunc,hWnd,uMsg,wParam,lParam) 

      Default 
        result = CallWindowProc_(lpPrevFunc,hWnd,uMsg,wParam,lParam) 

    EndSelect 
      
    ProcedureReturn result
EndProcedure 

CreateImage(0,300,220) 
StartDrawing(ImageOutput(0)) 
Box(0,0,310,230,#Gray) 
StopDrawing() 

OpenWindow(0,0,0,320,240,"PurePaint",#PB_Window_SystemMenu | #PB_Window_ScreenCentered) 
CreateGadgetList(WindowID(0)) 
ImageGadget(0,10,10,0,0,ImageID(0),0) 

lpPrevFunc = SetWindowLong_(GadgetID(0),#GWL_WNDPROC,@StaticProc()) 

While WaitWindowEvent() ! #PB_Event_CloseWindow : Wend 

Posted: Fri Apr 11, 2008 10:23 pm
by Fluid Byte
Yeah, I always forget to return from procedure. Had a similar issue a while ago where an OD ListView gadget still was showing the focus rect because I didn't returned from the #WM_DRAWITEM message. Keept me busy for at least for two hours.