Image Priority

Blitz3D Forums/Blitz3D Programming/Image Priority

I am creating a GUI and was wondering if there is a command to perform Image priority, so that if you clicked on one image it would draw that on top of the other and hide the previous image and related hotspots underneath. This means the image underneath may be partially obscured by the one on top and classed as inactive.

Is there a way of managing the partial obscurity so that if I clicked on the partially seen image underneath, it would appear on top and become active......If you know what i mean...

So no help on this?

I am not sure its possible but there may be a workaround?

If it is unclear, I can try and clarify...

This should be pretty simple.

I'd make each image thingy a type so that the postition of each one in the list represents it's 'priority': the first in the list has lowest priority (is drawn first) and the last has highest (drawn last). You can then just use a For/Each loop to draw them in the correct order.

You can then run through the type list backwards to check for a click on each one. As soon as you find an image that has been clicked, make it top priority by moving it to the end of the type list (using 'Insert clicked_thingy After Last thingy_type'). Doing so this way will automatically handle overlapping images correctly.

[edit] OK, I got bored so here's a simple demo of the technique I'm talking about. :)
	Graphics 500,500,0,2
	SetBuffer BackBuffer()
	SeedRnd MilliSecs()
	
	Type thingyT
		Field x%, y%
		Field width%, height%
		Field r%, g%, b%
	End Type
	
	For n = 1 To 50
		this.thingyT = New thingyT
		this\width = Rand(30,100)
		this\height = Rand(30,100)
		this\x = Rand(0,500-this\width)
		this\y = Rand(0,500-this\height)
		this\r = Rand(20,255)
		this\g = Rand(20,255)
		this\b = Rand(20,255)
	Next
	
	While Not KeyHit(1)
		Cls
		If MouseHit(1) Then update_thingies()
		draw_thingies()
		Flip
	Wend
	
	End	

Function update_thingies()

	mx = MouseX()
	my = MouseY()
	
	this.thingyT = Last thingyT

	While this <> Null
		If (mx >= this\x) And (mx <= (this\x+this\width-1))	
			If (my >= this\y) And (my <= (this\y+this\height-1))	
				; This thingy has been clicked on so make it top thingy.
				Insert this After Last thingyT
				Return
			EndIf
		EndIf
		
		this = Before this
	Wend	

End Function

Function draw_thingies()

	For this.thingyT = Each thingyT
		Color this\r,this\g,this\b
		Rect this\x,this\y,this\width,this\height,True
		Color 255,255,255
		Rect this\x,this\y,this\width,this\height,False
	Next
	
End Function


Hi big10p

Thanks for the response. I have the priority part working. What I am having trouble with is managing the hotspots associated with the images.

For instance at the top of the image I have a bar which can be clicked on (hotspot) to bring that image to the front. If it comes to the top and an another image is hidden behind, the hotspots on the underneath image can still be activated. Is there a way of preventing this if the top image obscures the bottom. Could imageoverlap help?

PPS - Thanks of the code example, I will have a go at this..

Have you tried the demo I just posted? You may have missed it as we posted at about the same time.

I think it does what you want, or maybe I'm still not getting what you mean? :)

Fantastic, this is just the ticket. Incredible type management!!!

I am just exploring the benefits of types. I was a bit unsure on how to manage the list of images. It solves the problem...:-)

It may be a good idea to put this in the code examples section.

Thanks big10p

No problem. OK, I'll stick it in the code archives for anyone else who may find it useful. :)

Sorry to ask again big10p (or anyone) but is there an easy way to modify the code so that if I clicked on the topthingy shape, you would be able to move it around the screen to a new location. i.e mousedown, drag then releasemouse to drop.

From my own thinking, I could add an extra field to the Type, something like Field id% to track which shape thing in the type is on top, then move it. Is this the best way?

Thanks

Here's some code, it's pretty ancient, so probably not the best example but it should give you some sort of idea...
;Window Z order

Type window
	Field win_id, win_title$
	Field win_x, win_y, win_w, win_h
	Field gad_num, gad_id[99]
End Type

Type gadget
	Field parent, gad_id, gad_type, gad_state
	Field gad_x, gad_y, gad_w, gad_h
	Field gad_r, gad_g, gad_b
End Type
 
Graphics 800, 600, 0, 2
SetBuffer BackBuffer()

SeedRnd MilliSecs()

example_windows(10)

winfont = LoadFont("arial bold", 16)
SetFont winfont

omx = MouseX()
omy = MouseY()
drag = 0
focus = 1
w.window = Last window

Repeat
	mx = MouseX()
	my = MouseY()
	lmb_click = MouseHit(1)
	lmb_down = MouseDown(1)
		
	; get focus
	If lmb_click Or drag
		If drag = 0
			focus = update_windows_z(mx, my, lmb_down)
			If focus
				w.window = Last window
				If (focus = 2)
					drag = 1
				EndIf
			EndIf
		Else
			w\win_x = w\win_x + (mx - omx)
			w\win_y = w\win_y + (my - omy)
			If (Not lmb_down) Then drag = 0
		EndIf
		omx = mx
		omy = my
	EndIf
	
	;get gadget
	If focus = 1
		g.gadget = update_gadgets(w, mx, my, lmb_down)
	EndIf
	
	If g <> Null Then gad_ret = g\gad_id
	
	Cls
	
	draw_windows(focus)
	
	Color 0, 200, 0
	Text 0, 0, "Window : " + w\win_id
	Text 0, 10, "Focus : " + focus
	Text 0, 30, "Down : " + lmb_down
	Text 0, 50, "Clicked : " + gad_ret
	
	Flip
Until KeyDown(1)

End


Function example_windows(num)
	Local wh
	For x = 1 To num
		wh = create_window(Rand(600), Rand(400), 200, 200, "Window No " + x)
		create_gadget(wh, 0, Rand(2, 138), Rand(20, 178), 60, 20)
	Next
End Function

Function create_gadget(wh, gt, gx, gy, gw, gh)
	Local g.gadget, w.window
	g.gadget = New gadget
	g\parent = wh
	g\gad_id = Handle(g)
	g\gad_type = gt
	g\gad_x = gx
	g\gad_y = gy
	g\gad_w = gw
	g\gad_h = gh
	g\gad_state = 0
	w.window = Object.window(wh)
	w\gad_id[w\gad_num] = g\gad_id
	w\gad_num = w\gad_num + 1
	Return g\gad_id
End Function

Function update_gadgets.gadget(w.window, mx, my, l_down)
	Local g.gadget, gc
	If l_down
		If w\gad_num
			For gc=0 To w\gad_num - 1
				g = Object.gadget(w\gad_id[gc])
				If RectsOverlap(mx, my, 1, 1, w\win_x + g\gad_x, w\win_y + g\gad_y, g\gad_w, g\gad_h)
					g\gad_state = 1
				Else
					g\gad_state = 0
				EndIf	
			Next
		EndIf
	Else
		If w\gad_num
			For gc=0 To w\gad_num - 1
				g = Object.gadget(w\gad_id[gc])
				If g\gad_state = 1 
					g\gad_state = 0
					Return g
				EndIf	
			Next
		EndIf
	EndIf
End Function

Function draw_gadget(w.window, g.gadget)
	Select g\gad_type
		Case 0
			If g\gad_state = 0
				Color 75, 75, 75
				Rect w\win_x + g\gad_x + 1, w\win_y + g\gad_y + 1, g\gad_w - 1, g\gad_h - 1, 0		
				Color 200, 200, 200
				Rect w\win_x + g\gad_x, w\win_y + g\gad_y, g\gad_w - 1, g\gad_h - 1, 0
				Color 150, 150, 150
				Rect w\win_x + g\gad_x + 1, w\win_y + g\gad_y + 1, g\gad_w - 2, g\gad_h - 2, 1	
			Else	
				Color 75, 75, 75
				Rect w\win_x + g\gad_x, w\win_y + g\gad_y, g\gad_w - 1, g\gad_h - 1, 0
				Color 200, 200, 200
				Rect w\win_x + g\gad_x + 1, w\win_y + g\gad_y + 1, g\gad_w - 1, g\gad_h - 1, 0
				Color 145, 145, 145
				Rect w\win_x + g\gad_x + 1, w\win_y + g\gad_y + 1, g\gad_w - 2, g\gad_h - 2, 1
			EndIf
	End Select
End Function
								
Function create_window(wx, wy, ww, wh, wt$)
	Local w.window
	w.window = New window
	w\win_id = Handle(w)
	w\win_title$ = wt$
	w\win_x = wx
	w\win_y = wy
	w\win_w = ww
	w\win_h = wh
	w\gad_num = 0
	Return w\win_id
End Function

Function draw_windows(f)
	Local g, l.window
	l.window = Last window
	For w.window = Each window
		Color 100, 100, 100 
		Rect w\win_x, w\win_y, w\win_w, w\win_h, 1
		Color 75, 75, 75
		Rect w\win_x + 1, w\win_y + 18, w\win_w - 1, w\win_h - 18, 0		
		Color 200, 200, 200
		Rect w\win_x, w\win_y, w\win_w - 1, w\win_h - 1, 0
		If (l = w) And (f > 0) ; top window and focus
			Color 150, 150, 170
			Rect w\win_x + 1, w\win_y + 1, w\win_w - 2, 17, 1
			Color 220, 220, 220
			Text w\win_x + 4, w\win_y + 1, w\win_title$
		Else	
			Color 150, 150, 150
			Rect w\win_x + 1, w\win_y + 1, w\win_w - 2, 17, 1
			Color 120, 120, 120
			Text w\win_x + 4, w\win_y + 1, w\win_title$
		EndIf
		If w\gad_num
			For g=0 To w\gad_num - 1
				draw_gadget(w, Object.gadget(w\gad_id[g]))
			Next
		EndIf
	Next
End Function

Function update_windows_z(x, y, l_down)
	Local w.window
	w.window = Last window
	While w <> Null
		If RectsOverlap(x, y, 1, 1, w\win_x, w\win_y, w\win_w, w\win_h)
			Insert w After Last window
			If l_down
				If (y >= w\win_y) And (y <= (w\win_y + 18))
					Return 2 ; drag
				Else
					Return 1 ; focus
				EndIf
			EndIf
		EndIf
		w = Before w
	Wend
End Function


Yan,

Thanks for the post. A good example of Z priority for 2D windowing. I see you are using an ID system to manage the state of the windows and gadgets and tracking this...

Instead of drawing the windows I will be using images of certain sizes.

This gives me a good idea. Thanks again.

Spriteman, in the code I posted, there's no need to store IDs to track the top thingy/window. Because of the way the list is organized, the top thingy is always the last one in the list, so, to get it, just do something like:
top_thingy.thingyT = Last thingyT


OK, here's my amended code to allow the thingies to be dragged around.
	Graphics 500,500,0,2
	SetBuffer BackBuffer()
	SeedRnd MilliSecs()
	
	Type thingyT
		Field x%, y%
		Field width%, height%
		Field r%, g%, b%
	End Type
	
	For n = 1 To 50
		this.thingyT = New thingyT
		this\width = Rand(30,100)
		this\height = Rand(30,100)
		this\x = Rand(0,500-this\width)
		this\y = Rand(0,500-this\height)
		this\r = Rand(20,255)
		this\g = Rand(20,255)
		this\b = Rand(20,255)
	Next

	Global mx, my
	Global clicked_thingy.thingyT
	
	While Not KeyHit(1)

		mx = MouseX()
		my = MouseY()

		Cls
		
		If MouseHit(1)
			update_thingies()
			If clicked_thingy <> Null
				; Find distance from mouse pointer to top-left of clicked thingy.
				offset_x = mx - clicked_thingy\x
				offset_y = my - clicked_thingy\y
			EndIf
		EndIf
		
		If MouseDown(1) And (clicked_thingy <> Null)
			; Drag: position clicked thingy relative to mouse position.
			clicked_thingy\x = mx - offset_x
			clicked_thingy\y = my - offset_y
		EndIf
		
		draw_thingies()
		Flip
	Wend
	
	End	

Function update_thingies()

	this.thingyT = Last thingyT

	While this <> Null
		If (mx >= this\x) And (mx <= (this\x+this\width-1))	
			If (my >= this\y) And (my <= (this\y+this\height-1))	
				; This thingy has been clicked on so make it top thingy.
				Insert this After Last thingyT
				clicked_thingy = Last thingyT
				Return
			EndIf
		EndIf
		
		this = Before this
	Wend	

	; No thingy was clicked on.
	clicked_thingy = Null

End Function

Function draw_thingies()

	For this.thingyT = Each thingyT
		Color this\r,this\g,this\b
		Rect this\x,this\y,this\width,this\height,True
		Color 255,255,255
		Rect this\x,this\y,this\width,this\height,False
	Next
	
End Function