Unlimited events (Canvas inside ScrollArea)

Post bugreports for the Windows version here
Sergey
User
User
Posts: 95
Joined: Wed Jan 12, 2022 2:41 pm

Unlimited events (Canvas inside ScrollArea)

Post by Sergey »

Hi,
Add boxes to create a scroll
Hover your mouse over any box
Events fire when the mouse moves

Now scroll down to the very bottom
Hover your mouse over any box
Events don't stop :(

PureScrollArea and PureCanvas are custom window classes
And maybe bug inside it

Tested on Win10x64 PB630x64

Code: Select all

EnableExplicit

#window = 0

#window_width = 300
#window_height = 400
#window_margin = 5

#button_width = 80
#button_height = 25

#boxes_width = 200
#boxes_height = 50
#boxes_borders = 4

Enumeration; gadgets
	#button	
	#scrollarea
	#canvas
EndEnumeration

Structure boxes_list
	color.l
	y.i
	h.i
	selected.b
EndStructure

NewList boxes.boxes_list()

Define window_handle

Define vscroll_size, hscroll_size

Declare redraw_boxes()

;- procedures

Procedure resize_window()
	Shared window_handle
	
	Protected window_width, window_height
	
	window_width = WindowWidth(#window)
	window_height = WindowHeight(#window)
	
	ResizeGadget(#scrollarea, window_width - #boxes_width - #window_margin, #window_margin, #boxes_width, window_height - #window_margin * 2)
	
	redraw_boxes()
EndProcedure

Procedure.b open_window()
	Shared window_handle
	
	Protected result.b
	
	window_handle = OpenWindow(#window, #PB_Ignore, #PB_Ignore, #window_width, #window_height, "unlimited events", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
	If window_handle		
		ButtonGadget(#button, 5, 5, #button_width, #button_height, "Add box")
		
		ScrollAreaGadget(#scrollarea, 0, 0, 0, 0, 0, 0, #PB_ScrollArea_BorderLess)
		CanvasGadget(#canvas, 0, 0, 0, 0)
		CloseGadgetList()

		WindowBounds(#window, #window_width, #window_height, #PB_Ignore, #PB_Ignore)
		SmartWindowRefresh(#window, #True)
		BindEvent(#PB_Event_SizeWindow, @resize_window(), #window)
		
		result = #True
	EndIf
	
	ProcedureReturn result
EndProcedure

Procedure redraw_boxes()
	Shared boxes()
	Shared vscroll_size
	
	Protected boxes_height
	Protected vscroll_enabled.b
	
	If GadgetHeight(#scrollarea) > 0
		ForEach boxes()
			boxes_height + #boxes_height
		Next
		
		If boxes_height > GadgetHeight(#scrollarea) - #boxes_borders
			vscroll_enabled = #True
			
			SetGadgetAttribute(#scrollarea, #PB_ScrollArea_InnerWidth, #boxes_width - DesktopUnscaledX(#boxes_borders) - DesktopUnscaledX(vscroll_size))
			SetGadgetAttribute(#scrollarea, #PB_ScrollArea_InnerHeight, boxes_height)
			
			ResizeGadget(#canvas, 0, 0, #boxes_width - DesktopUnscaledX(#boxes_borders) - DesktopUnscaledX(vscroll_size), boxes_height)
			Debug "REDRAW with SCROLL " + Str(ElapsedMilliseconds())
		Else
			SetGadgetAttribute(#scrollarea, #PB_ScrollArea_InnerWidth, #boxes_width - DesktopUnscaledX(#boxes_borders))
			SetGadgetAttribute(#scrollarea, #PB_ScrollArea_InnerHeight, boxes_height)
			
			ResizeGadget(#canvas, 0, 0, #boxes_width - DesktopUnscaledX(#boxes_borders), boxes_height)
			Debug "REDRAW " + Str(ElapsedMilliseconds())
		EndIf
		
		If StartDrawing(CanvasOutput(#canvas))			
			boxes_height = 0
			ForEach boxes()			
				boxes()\y = DesktopScaledY(boxes_height)
				boxes_height + #boxes_height
				boxes()\h = DesktopScaledY(boxes_height) - boxes()\y
			Next
			
			ForEach boxes()			
				If boxes()\selected = #True
					Box(0, boxes()\y, DesktopScaledX(GadgetWidth(#canvas)), boxes()\h, RGB(Red(boxes()\color) * 0.5, Green(boxes()\color) * 0.5, Blue(boxes()\color) * 0.5))
				Else				
					Box(0, boxes()\y, DesktopScaledX(GadgetWidth(#canvas)), boxes()\h, boxes()\color)
				EndIf
			Next	
			
			StopDrawing()
		EndIf
	EndIf
EndProcedure

Procedure add_box()
	Shared boxes()
	
	AddElement(boxes())
	boxes()\color = RGB(Random(255, 100), Random(255, 100), Random(255, 100))

	redraw_boxes()
EndProcedure

Procedure canvas_boxes(event_type)
	Shared boxes()
	
	Protected mouse_x, mouse_y
	
	Select event_type
	Case  #PB_EventType_MouseLeave
		ForEach boxes()
			boxes()\selected = #False
		Next
		
		redraw_boxes()
		
	Case #PB_EventType_MouseMove
		mouse_x = GetGadgetAttribute(#canvas, #PB_Canvas_MouseX)
		mouse_y = GetGadgetAttribute(#canvas, #PB_Canvas_MouseY)

		ForEach boxes()
			If mouse_y >= boxes()\y And mouse_y <= boxes()\y + boxes()\h - 1
				boxes()\selected = #True
			Else
				boxes()\selected = #False
			EndIf
		Next
		
		redraw_boxes()
	EndSelect
EndProcedure

Procedure main_loop()
	Shared window_handle
	Shared boxes()
	
	Repeat
		Select WaitWindowEvent()			
		Case #PB_Event_Gadget
			Select EventGadget()
			Case #button: add_box()
			Case #canvas: canvas_boxes(EventType())
			EndSelect
			
		Case #PB_Event_CloseWindow
			Break
		EndSelect
	ForEver
	
	If window_handle
		CloseWindow(#window)
	EndIf
EndProcedure

;- main code
vscroll_size = GetSystemMetrics_(#SM_CXVSCROLL)

If open_window()	
	resize_window()
	main_loop()
EndIf

End
breeze4me
Enthusiast
Enthusiast
Posts: 674
Joined: Thu Mar 09, 2006 9:24 am
Location: S. Kor

Re: Unlimited events (Canvas inside ScrollArea)

Post by breeze4me »

When a call to SetGadgetAttribute(gadget, #PB_ScrollArea_InnerWidth, ...) or
SetGadgetAttribute(gadget, #PB_ScrollArea_InnerHeight, ...) not only changes the size of the scroll area gadget's child control, but also resets its x and y coordinates to 0,0 before scrolling.
PB internal call: MoveWindow(hwndScrChild, 0, 0, rt.right, rt.bottom, 1)
Afterwards, the internal child control scrolls.

This causes the canvas gadget to move along with them. Consequently, the canvas's mouse coordinates change, triggering continuous events.

Code: Select all

EnableExplicit

#window = 0

#window_width = 300
#window_height = 400
#window_margin = 5

#button_width = 80
#button_height = 25

#boxes_width = 200
#boxes_height = 50
#boxes_borders = 4

Enumeration; gadgets
	#button	
	#scrollarea
	#canvas
EndEnumeration

Structure boxes_list
	color.l
	y.i
	h.i
	selected.b
EndStructure

NewList boxes.boxes_list()

Define window_handle

Define vscroll_size, hscroll_size

Declare redraw_boxes()

;- procedures

Procedure resize_window()
	Shared window_handle
	
	Protected window_width, window_height
	
	window_width = WindowWidth(#window)
	window_height = WindowHeight(#window)
	
	ResizeGadget(#scrollarea, window_width - #boxes_width - #window_margin, #window_margin, #boxes_width, window_height - #window_margin * 2)
	
	redraw_boxes()
EndProcedure

Global PrevWndProcScrChild

Procedure WndProcScrChild(hWnd, uMsg, wParam, lParam)
  
  If uMsg = #WM_WINDOWPOSCHANGING
    Protected *wp.WINDOWPOS = lParam
    If *wp
      Debug "child x,y = " + *wp\x + " , " + *wp\y
    EndIf
  EndIf
  
  ProcedureReturn CallWindowProc_(PrevWndProcScrChild, hWnd, uMsg, wParam, lParam)
EndProcedure

Procedure.b open_window()
	Shared window_handle
	
	Protected result.b
	
	window_handle = OpenWindow(#window, #PB_Ignore, #PB_Ignore, #window_width, #window_height, "unlimited events", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
	If window_handle		
		ButtonGadget(#button, 5, 5, #button_width, #button_height, "Add box")
		
		ScrollAreaGadget(#scrollarea, 0, 0, 0, 0, 0, 0, 0, #PB_ScrollArea_BorderLess)
		CanvasGadget(#canvas, 0, 0, 0, 0)
		CloseGadgetList()
		
		PrevWndProcScrChild = SetWindowLongPtr_(GetWindow_(GadgetID(#scrollarea), #GW_CHILD), #GWLP_WNDPROC, @WndProcScrChild())
		
		WindowBounds(#window, #window_width, #window_height, #PB_Ignore, #PB_Ignore)
		SmartWindowRefresh(#window, #True)
		BindEvent(#PB_Event_SizeWindow, @resize_window(), #window)
		
		result = #True
	EndIf
	
	ProcedureReturn result
EndProcedure

Procedure redraw_boxes()
	Shared boxes()
	Shared vscroll_size
	
	Protected boxes_height
	Protected vscroll_enabled.b
	
	If GadgetHeight(#scrollarea) > 0
		ForEach boxes()
			boxes_height + #boxes_height
		Next
		
		Protected hChilld = GetWindow_(GadgetID(#scrollarea), #GW_CHILD)
		
		If boxes_height > GadgetHeight(#scrollarea) - #boxes_borders
			vscroll_enabled = #True
			
			SetGadgetAttribute(#scrollarea, #PB_ScrollArea_InnerWidth, #boxes_width - DesktopUnscaledX(#boxes_borders) - DesktopUnscaledX(vscroll_size))
			SetGadgetAttribute(#scrollarea, #PB_ScrollArea_InnerHeight, boxes_height)
      
			ResizeGadget(#canvas, 0, 0, #boxes_width - DesktopUnscaledX(#boxes_borders) - DesktopUnscaledX(vscroll_size), boxes_height)
; 			Debug "REDRAW with SCROLL " + Str(ElapsedMilliseconds())
		Else
			SetGadgetAttribute(#scrollarea, #PB_ScrollArea_InnerWidth, #boxes_width - DesktopUnscaledX(#boxes_borders))
			SetGadgetAttribute(#scrollarea, #PB_ScrollArea_InnerHeight, boxes_height)
			
			ResizeGadget(#canvas, 0, 0, #boxes_width - DesktopUnscaledX(#boxes_borders), boxes_height)
; 			Debug "REDRAW " + Str(ElapsedMilliseconds())
		EndIf
		
		If StartDrawing(CanvasOutput(#canvas))			
			boxes_height = 0
			ForEach boxes()			
				boxes()\y = DesktopScaledY(boxes_height)
				boxes_height + #boxes_height
				boxes()\h = DesktopScaledY(boxes_height) - boxes()\y
			Next
			
			ForEach boxes()			
				If boxes()\selected = #True
					Box(0, boxes()\y, DesktopScaledX(GadgetWidth(#canvas)), boxes()\h, RGB(Red(boxes()\color) * 0.5, Green(boxes()\color) * 0.5, Blue(boxes()\color) * 0.5))
				Else				
					Box(0, boxes()\y, DesktopScaledX(GadgetWidth(#canvas)), boxes()\h, boxes()\color)
				EndIf
			Next	
			
			StopDrawing()
		EndIf
	EndIf
EndProcedure

Procedure add_box()
	Shared boxes()
	
	AddElement(boxes())
	boxes()\color = RGB(Random(255, 100), Random(255, 100), Random(255, 100))

	redraw_boxes()
EndProcedure

Procedure canvas_boxes(event_type)
	Shared boxes()
	
	Protected mouse_x, mouse_y
	
	Select event_type
	Case  #PB_EventType_MouseLeave
		ForEach boxes()
			boxes()\selected = #False
		Next
		
		redraw_boxes()
		
	Case #PB_EventType_MouseMove
		mouse_x = GetGadgetAttribute(#canvas, #PB_Canvas_MouseX)
		mouse_y = GetGadgetAttribute(#canvas, #PB_Canvas_MouseY)

		ForEach boxes()
			If mouse_y >= boxes()\y And mouse_y <= boxes()\y + boxes()\h - 1
				boxes()\selected = #True
			Else
				boxes()\selected = #False
			EndIf
		Next
		
		redraw_boxes()
	EndSelect
EndProcedure

Procedure main_loop()
	Shared window_handle
	Shared boxes()
	
	Repeat
		Select WaitWindowEvent()			
		Case #PB_Event_Gadget
			Select EventGadget()
			Case #button: add_box()
			Case #canvas: canvas_boxes(EventType())
			EndSelect
			
		Case #PB_Event_CloseWindow
			Break
		EndSelect
	ForEver
	
	If window_handle
		CloseWindow(#window)
	EndIf
EndProcedure

;- main code
vscroll_size = GetSystemMetrics_(#SM_CXVSCROLL)

If open_window()	
	resize_window()
	main_loop()
EndIf

End
......
child x,y = 0 , 0
child x,y = 0 , -3
child x,y = 0 , -4
child x,y = 0 , -7
child x,y = 0 , -8
child x,y = 0 , -11
child x,y = 0 , -13
child x,y = 0 , -16
child x,y = 0 , -17
child x,y = 0 , -20
child x,y = 0 , -21
child x,y = 0 , -25
child x,y = 0 , -28
child x,y = 0 , -30
child x,y = 0 , -32
child x,y = 0 , -34
child x,y = 0 , -37
child x,y = 0 , -38
child x,y = 0 , -41
child x,y = 0 , -42
child x,y = 0 , -45
child x,y = 0 , -47
child x,y = 0 , -51
child x,y = 0 , -54
child x,y = 0 , -55
child x,y = 0 , -58
child x,y = 0 , -59
child x,y = 0 , -62
child x,y = 0 , -63
child x,y = 0 , -66
child x,y = 0 , -68
child x,y = 0 , -71
child x,y = 0 , -72
child x,y = 0 , -75
child x,y = 0 , -76
child x,y = 0 , -79
child x,y = 0 , -80
child x,y = 0 , -83
child x,y = 0 , -85
child x,y = 0 , -87
child x,y = 0 , -89
child x,y = 0 , -92
child x,y = 0 , -93
child x,y = 0 , -96
child x,y = 0 , -97
child x,y = 0 , -100
child x,y = 0 , -102
child x,y = 0 , -104
child x,y = 0 , -106
child x,y = 0 , -109
child x,y = 0 , -110
child x,y = 0 , -110
child x,y = 0 , -110
child x,y = 0 , 0
child x,y = 0 , -110
child x,y = 0 , 0
child x,y = 0 , -110
child x,y = 0 , 0
child x,y = 0 , -110
child x,y = 0 , 0
child x,y = 0 , -110
child x,y = 0 , 0
child x,y = 0 , -110
child x,y = 0 , 0
child x,y = 0 , -110
child x,y = 0 , 0
child x,y = 0 , -110
child x,y = 0 , 0
child x,y = 0 , -110
child x,y = 0 , 0
child x,y = 0 , -110
child x,y = 0 , 0
child x,y = 0 , -110
......
The workaround is as follows: only set the internal width or height when the internal width or height of the scroll area gadget differs.

Code: Select all

EnableExplicit

#window = 0

#window_width = 300
#window_height = 400
#window_margin = 5

#button_width = 80
#button_height = 25

#boxes_width = 200
#boxes_height = 50
#boxes_borders = 4

Enumeration; gadgets
	#button	
	#scrollarea
	#canvas
EndEnumeration

Structure boxes_list
	color.l
	y.i
	h.i
	selected.b
EndStructure

NewList boxes.boxes_list()

Define window_handle

Define vscroll_size, hscroll_size

Declare redraw_boxes()

;- procedures

Procedure resize_window()
	Shared window_handle
	
	Protected window_width, window_height
	
	window_width = WindowWidth(#window)
	window_height = WindowHeight(#window)
	
	ResizeGadget(#scrollarea, window_width - #boxes_width - #window_margin, #window_margin, #boxes_width, window_height - #window_margin * 2)
	
	redraw_boxes()
EndProcedure

Procedure.b open_window()
	Shared window_handle
	
	Protected result.b
	
	window_handle = OpenWindow(#window, #PB_Ignore, #PB_Ignore, #window_width, #window_height, "unlimited events", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
	If window_handle		
		ButtonGadget(#button, 5, 5, #button_width, #button_height, "Add box")
		
		ScrollAreaGadget(#scrollarea, 0, 0, 0, 0, 0, 0, #PB_ScrollArea_BorderLess)
		CanvasGadget(#canvas, 0, 0, 0, 0)
		CloseGadgetList()

		WindowBounds(#window, #window_width, #window_height, #PB_Ignore, #PB_Ignore)
		SmartWindowRefresh(#window, #True)
		BindEvent(#PB_Event_SizeWindow, @resize_window(), #window)
		
		result = #True
	EndIf
	
	ProcedureReturn result
EndProcedure

Procedure redraw_boxes()
	Shared boxes()
	Shared vscroll_size
	
	Protected boxes_height
	Protected vscroll_enabled.b
	
	If GadgetHeight(#scrollarea) > 0
		ForEach boxes()
			boxes_height + #boxes_height
		Next
		
		If boxes_height > GadgetHeight(#scrollarea) - #boxes_borders
			vscroll_enabled = #True
			
			
			If GetGadgetAttribute(#scrollarea, #PB_ScrollArea_InnerWidth) <> #boxes_width - DesktopUnscaledX(#boxes_borders) - DesktopUnscaledX(vscroll_size)
			  SetGadgetAttribute(#scrollarea, #PB_ScrollArea_InnerWidth, #boxes_width - DesktopUnscaledX(#boxes_borders) - DesktopUnscaledX(vscroll_size))
			EndIf
			If GetGadgetAttribute(#scrollarea, #PB_ScrollArea_InnerHeight) <> boxes_height
			  SetGadgetAttribute(#scrollarea, #PB_ScrollArea_InnerHeight, boxes_height)
			EndIf
			
			ResizeGadget(#canvas, 0, 0, #boxes_width - DesktopUnscaledX(#boxes_borders) - DesktopUnscaledX(vscroll_size), boxes_height)
			Debug "REDRAW with SCROLL " + Str(ElapsedMilliseconds())
		Else
		  If GetGadgetAttribute(#scrollarea, #PB_ScrollArea_InnerWidth) <> #boxes_width - DesktopUnscaledX(#boxes_borders)
			  SetGadgetAttribute(#scrollarea, #PB_ScrollArea_InnerWidth, #boxes_width - DesktopUnscaledX(#boxes_borders))
		  EndIf
			If GetGadgetAttribute(#scrollarea, #PB_ScrollArea_InnerHeight) <> boxes_height
			  SetGadgetAttribute(#scrollarea, #PB_ScrollArea_InnerHeight, boxes_height)
			EndIf
			
			ResizeGadget(#canvas, 0, 0, #boxes_width - DesktopUnscaledX(#boxes_borders), boxes_height)
			Debug "REDRAW " + Str(ElapsedMilliseconds())
		EndIf
		
		If StartDrawing(CanvasOutput(#canvas))			
			boxes_height = 0
			ForEach boxes()			
				boxes()\y = DesktopScaledY(boxes_height)
				boxes_height + #boxes_height
				boxes()\h = DesktopScaledY(boxes_height) - boxes()\y
			Next
			
			ForEach boxes()			
				If boxes()\selected = #True
					Box(0, boxes()\y, DesktopScaledX(GadgetWidth(#canvas)), boxes()\h, RGB(Red(boxes()\color) * 0.5, Green(boxes()\color) * 0.5, Blue(boxes()\color) * 0.5))
				Else				
					Box(0, boxes()\y, DesktopScaledX(GadgetWidth(#canvas)), boxes()\h, boxes()\color)
				EndIf
			Next	
			
			StopDrawing()
		EndIf
	EndIf
EndProcedure

Procedure add_box()
	Shared boxes()
	
	AddElement(boxes())
	boxes()\color = RGB(Random(255, 100), Random(255, 100), Random(255, 100))

	redraw_boxes()
EndProcedure

Procedure canvas_boxes(event_type)
	Shared boxes()
	
	Protected mouse_x, mouse_y
	
	Select event_type
	Case  #PB_EventType_MouseLeave
		ForEach boxes()
			boxes()\selected = #False
		Next
		
		redraw_boxes()
		
	Case #PB_EventType_MouseMove
		mouse_x = GetGadgetAttribute(#canvas, #PB_Canvas_MouseX)
		mouse_y = GetGadgetAttribute(#canvas, #PB_Canvas_MouseY)

		ForEach boxes()
			If mouse_y >= boxes()\y And mouse_y <= boxes()\y + boxes()\h - 1
				boxes()\selected = #True
			Else
				boxes()\selected = #False
			EndIf
		Next
		
		redraw_boxes()
	EndSelect
EndProcedure

Procedure main_loop()
	Shared window_handle
	Shared boxes()
	
	Repeat
		Select WaitWindowEvent()			
		Case #PB_Event_Gadget
			Select EventGadget()
			Case #button: add_box()
			Case #canvas: canvas_boxes(EventType())
			EndSelect
			
		Case #PB_Event_CloseWindow
			Break
		EndSelect
	ForEver
	
	If window_handle
		CloseWindow(#window)
	EndIf
EndProcedure

;- main code
vscroll_size = GetSystemMetrics_(#SM_CXVSCROLL)

If open_window()	
	resize_window()
	main_loop()
EndIf

End
Sergey
User
User
Posts: 95
Joined: Wed Jan 12, 2022 2:41 pm

Re: Unlimited events (Canvas inside ScrollArea)

Post by Sergey »

Hi, breeze4me
Thank you very much for such a detailed description of this situation and the solution found,
also for the missing 0 in the ScrollAreaGadget parameters :D
User avatar
mk-soft
Always Here
Always Here
Posts: 6605
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Unlimited events (Canvas inside ScrollArea)

Post by mk-soft »

Nice code

Small optimisation. It does not need to be redrawn with every mouse movement,
but only when the selection changes. Extension of the box data not last_selected

Code: Select all

EnableExplicit

#window = 0

#window_width = 300
#window_height = 400
#window_margin = 5

#button_width = 80
#button_height = 25

#boxes_width = 200
#boxes_height = 50
#boxes_borders = 4

Enumeration; gadgets
	#button	
	#scrollarea
	#canvas
EndEnumeration

Structure boxes_list
	color.l
	y.i
	h.i
	selected.l
	last_selected.l
EndStructure

NewList boxes.boxes_list()

Define window_handle

Define vscroll_size, hscroll_size

Declare redraw_boxes()

;- procedures

Procedure resize_window()
	Shared window_handle
	
	Protected window_width, window_height
	
	window_width = WindowWidth(#window)
	window_height = WindowHeight(#window)
	
	ResizeGadget(#scrollarea, window_width - #boxes_width - #window_margin, #window_margin, #boxes_width, window_height - #window_margin * 2)
	
	redraw_boxes()
EndProcedure

Procedure.b open_window()
	Shared window_handle
	
	Protected result.b
	
	window_handle = OpenWindow(#window, #PB_Ignore, #PB_Ignore, #window_width, #window_height, "unlimited events", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
	If window_handle		
		ButtonGadget(#button, 5, 5, #button_width, #button_height, "Add box")
		
		ScrollAreaGadget(#scrollarea, 0, 0, 0, 0, 0, 0, #PB_ScrollArea_BorderLess)
		CanvasGadget(#canvas, 0, 0, 0, 0)
		CloseGadgetList()

		WindowBounds(#window, #window_width, #window_height, #PB_Ignore, #PB_Ignore)
		SmartWindowRefresh(#window, #True)
		BindEvent(#PB_Event_SizeWindow, @resize_window(), #window)
		
		result = #True
	EndIf
	
	ProcedureReturn result
EndProcedure

Procedure redraw_boxes()
	Shared boxes()
	Shared vscroll_size
	
	Protected boxes_height
	Protected vscroll_enabled.b
	
	If GadgetHeight(#scrollarea) > 0
		ForEach boxes()
			boxes_height + #boxes_height
		Next
		
		If boxes_height > GadgetHeight(#scrollarea) - #boxes_borders
			vscroll_enabled = #True
			
			
			If GetGadgetAttribute(#scrollarea, #PB_ScrollArea_InnerWidth) <> #boxes_width - DesktopUnscaledX(#boxes_borders) - DesktopUnscaledX(vscroll_size)
			  SetGadgetAttribute(#scrollarea, #PB_ScrollArea_InnerWidth, #boxes_width - DesktopUnscaledX(#boxes_borders) - DesktopUnscaledX(vscroll_size))
			EndIf
			If GetGadgetAttribute(#scrollarea, #PB_ScrollArea_InnerHeight) <> boxes_height
			  SetGadgetAttribute(#scrollarea, #PB_ScrollArea_InnerHeight, boxes_height)
			EndIf
			
			ResizeGadget(#canvas, 0, 0, #boxes_width - DesktopUnscaledX(#boxes_borders) - DesktopUnscaledX(vscroll_size), boxes_height)
			Debug "REDRAW with SCROLL " + Str(ElapsedMilliseconds())
		Else
		  If GetGadgetAttribute(#scrollarea, #PB_ScrollArea_InnerWidth) <> #boxes_width - DesktopUnscaledX(#boxes_borders)
			  SetGadgetAttribute(#scrollarea, #PB_ScrollArea_InnerWidth, #boxes_width - DesktopUnscaledX(#boxes_borders))
		  EndIf
			If GetGadgetAttribute(#scrollarea, #PB_ScrollArea_InnerHeight) <> boxes_height
			  SetGadgetAttribute(#scrollarea, #PB_ScrollArea_InnerHeight, boxes_height)
			EndIf
			
			ResizeGadget(#canvas, 0, 0, #boxes_width - DesktopUnscaledX(#boxes_borders), boxes_height)
			Debug "REDRAW " + Str(ElapsedMilliseconds())
		EndIf
		
		If StartDrawing(CanvasOutput(#canvas))			
			boxes_height = 0
			ForEach boxes()			
				boxes()\y = DesktopScaledY(boxes_height)
				boxes_height + #boxes_height
				boxes()\h = DesktopScaledY(boxes_height) - boxes()\y
			Next
			
			ForEach boxes()			
				If boxes()\selected = #True
					Box(0, boxes()\y, DesktopScaledX(GadgetWidth(#canvas)), boxes()\h, RGB(Red(boxes()\color) * 0.5, Green(boxes()\color) * 0.5, Blue(boxes()\color) * 0.5))
				Else				
					Box(0, boxes()\y, DesktopScaledX(GadgetWidth(#canvas)), boxes()\h, boxes()\color)
				EndIf
			Next	
			
			StopDrawing()
		EndIf
	EndIf
EndProcedure

Procedure add_box()
	Shared boxes()
	
	AddElement(boxes())
	boxes()\color = RGB(Random(255, 100), Random(255, 100), Random(255, 100))

	redraw_boxes()
EndProcedure

Procedure canvas_boxes(event_type)
  Protected redraw
  Shared boxes()
	
	Protected mouse_x, mouse_y
	
	Select event_type
	Case  #PB_EventType_MouseLeave
		ForEach boxes()
		  boxes()\selected = #False
		  boxes()\last_selected = #False
		  
		Next
		
		redraw_boxes()
		
	Case #PB_EventType_MouseMove
		mouse_x = GetGadgetAttribute(#canvas, #PB_Canvas_MouseX)
		mouse_y = GetGadgetAttribute(#canvas, #PB_Canvas_MouseY)

		ForEach boxes()
		  If mouse_y >= boxes()\y And mouse_y <= boxes()\y + boxes()\h - 1
		    boxes()\selected = #True
			Else
				boxes()\selected = #False
			EndIf
			If boxes()\last_selected <> boxes()\selected
			  boxes()\last_selected = boxes()\selected
			  redraw = #True
			EndIf
		Next
		
		If redraw
		  redraw_boxes()
		EndIf
	EndSelect
EndProcedure

Procedure main_loop()
	Shared window_handle
	Shared boxes()
	
	Repeat
		Select WaitWindowEvent()			
		Case #PB_Event_Gadget
			Select EventGadget()
			Case #button: add_box()
			Case #canvas: canvas_boxes(EventType())
			EndSelect
			
		Case #PB_Event_CloseWindow
			Break
		EndSelect
	ForEver
	
	If window_handle
		CloseWindow(#window)
	EndIf
EndProcedure

;- main code
vscroll_size = GetSystemMetrics_(#SM_CXVSCROLL)

If open_window()	
	resize_window()
	main_loop()
EndIf

End
My Projects EventDesigner V3 / ThreadToGUI / OOP-BaseClass / Windows: Module ActiveScript
PB v3.30 / v5.75 - OS Mac Mini - VM Window Pro / Linux Ubuntu
Downloads on my OneDrive
Sergey
User
User
Posts: 95
Joined: Wed Jan 12, 2022 2:41 pm

Re: Unlimited events (Canvas inside ScrollArea)

Post by Sergey »

Hi, mk-soft
Thanks for your words
You're right and understood the logic of code execution and made precise optimization

My idea was to show that by changing the gadget attribute when the scroll is in the zero position, the program logic works fine, but as soon as you move the scroll down, endless redraws begin

You can do optimizations or you can add a check for resizing using SetGadgetAttribute

By example, gadget height was 500, change it to 500, that is we don’t change anything, so there’s no need to redraw
I could be wrong, but every native command in the language should be protected from fools like me who forgot to do an If check :lol:
Post Reply