your own gadgets! (Blitzplus, average skills)
BlitzPlus Forums/BlitzPlus Tutorials/your own gadgets! (Blitzplus, average skills)| 
 | ||
| When the B+ gadgets don't satisfy your needs anymore, and you fear that BlitzMax will still take a while, then read on! Using banks, you can do your own gadgets, which can be way more advanced than any 'internal' gadget. The basic idea is that you store all your gadget-properties in a bank, and use the bankhandle for everything gadget-related (drawing, modifying etc.) Compare: window=CreateWindow("title",0,0,640,480) with bla=CreateSomething(32,32,64,24,window) From this perspective, working with banks is the most clean method to do your own gadgets. And after adding "CreateSomething(x,y,width,height,parent)" to a .decl file to make it highlight in your code, it feels like you're working with an internal gadget! The only 2 downsides are that you need your own events-checks and that the normal gadget modifers (SetGadgetShape etc. etc.) won't work on these new gadgets). But personally I'd say these downsides are really no match for all the possible goodies that are in store for you! Basically there're several functions that you always need: - a create function - an update function and if the function should react to events then you need another one: - an event function additionally, if you wish to read or write properties of your gadget then you need these 2 functions aswell: - get functions - set functions A create function creates a bank for you in which to store all your properties. An update function draws your gadget. An event function does all the event handling and can modify your gadget properties. And set & get functions write or read properties. Note that once you created your own gadget, the gadget handle is the only variable you'll ever need in your source. You don't need globals or other vars, for the simple reason that all vars are stored inside the gadget-bank. Another example of custom gadget I already made is a window. This window has a border based on a bitmap and with a get function you get back the panel of that custom window. On this panel you can place blitz gadgets or your own gadgets. With a little effort you can make a gadget that contains even more gadgets. In this case the sub-gadget event-checks are inside the parent event-checks. In short, a scrollbar would be made out of 1 main gadget with 3 subgadgets (an up-button, a down-button and the scrollbar itself). This works perfectly! And you need only one event function call in your mainloop. With a little more creativity you can load images inside a create-function, and store the image-handles inside the bank. A primitive image-button is within everyone's reach then. There are more ways to enhance the whole gadget system. You could for example use the first 4 bytes of each bank to store some ID. By checking on the ID you can make sure that you don't accidentaly send the wrong bankhandle to an eventchecker, updater or get/set. Gadgets can be complete large objects, one of my own gadgets is a complete zoom window (to draw tiles/sprites). Once I created it, and once I put an events checker in my mainloop I can draw in it with 2 colors! This way, building apps is a piece o' cake! The source below is as small as possible, without all the comfy extras, to make it a bit more readable. The color-system could be somewhat more advanced as well (didn't want to spend more than a few seconds to it :), but the whole idea is clear. 
;
; your own gadgets in Blitzplus using banks
;
; tutorial by CS^TBL - 2004
;
app=CreateWindow("gadget example",0,0,640,480)
; a single something
something=CreateSomething(32,32,64,24,app,80,120,160)
; an array of somethings  (nice way to do a virtual drumcomputer this way ^^;)
Dim bla(31)
For t=0 To 31
	bla(t)=CreateSomething(32+(t*16),128,16,32,app,192,0,0) ; create a row of somethings
	
	If Rnd(1,5)<2 SetSomethingState(bla(t),True) ; switch on a few
	
Next
;----------------------------------------------------------------------------------------------------
; ----- MAIN loop -----------------------------------------------------------------------------------
;----------------------------------------------------------------------------------------------------
quit=False
Repeat
	WaitEvent()
	If EventID()=$803 quit=True
	; check on events
	SomethingEvents(something)
	
	For t=0 To 31
		SomethingEvents(bla(t))
	Next
	
Until quit
;----------------------------------------------------------------------------------------------------
;----------------------------------------------------------------------------------------------------
; and free all the somethings again
FreeBank something
For t=0 To 31
	FreeBank bla(t)
Next
End ; bye!
;----------------------------------------------------------------------------------------------------
Function GetSomethingState(bank)
	If BankSize(bank)<8 End
	Return PeekByte(bank,4)
End Function
;----------------------------------------------------------------------------------------------------
Function SetSomethingState(bank,state)
	If BankSize(bank)<8 End
	PokeByte bank,4,state 
	UpdateSomething(bank)
End Function
;----------------------------------------------------------------------------------------------------
Function SomethingEvents(bank)
	If BankSize(bank)<8 End
	canvas=PeekInt(bank,0)
	status=PeekByte(bank,4)
	
	If EventSource()=canvas
	
		If EventID()=$201
		
			If EventData()=1
				status=(status+1) Mod 2
				
				PokeByte bank,4,status
				
				UpdateSomething(bank)
			EndIf
		EndIf
	
	EndIf	
End Function
;----------------------------------------------------------------------------------------------------
Function UpdateSomething(bank)
	If BankSize(bank)<8 End
	canvas=PeekInt(bank,0)
	status=PeekByte(bank,4)
	r=PeekByte(bank,5)
	g=PeekByte(bank,6)
	b=PeekByte(bank,7)
	
	width=GadgetWidth(canvas)
	height=GadgetHeight(canvas)
	
	SetBuffer CanvasBuffer(canvas)
	
		Color 0,0,0:Rect 0,0,width,height,False
		Color 255,255,255:Rect 1,1,width-2,height-2,False
		
		r=Limit(r+(status*64),0,255)
		g=Limit(g+(status*64),0,255)
		b=Limit(b+(status*64),0,255)
		Color r,g,b
		Rect 2,2,width-4,height-4,True
		
	FlipCanvas canvas
End Function
;----------------------------------------------------------------------------------------------------
Function CreateSomething(x,y,width,height,parent,r,g,b)
	; adr	name			size
	; --------------------------------------
	; 00	canvas		1 int ( 4 bytes)
	; 04	status		1 byte
	; 05	red			1 byte
	; 06	greens		1 byte
	; 07	blue			1 byte
	;
	; total: 8 bytes
	
	bank=CreateBank(8)
	canvas=CreateCanvas(x,y,width,height,parent)
	
	PokeInt bank,0,canvas
	PokeByte bank,4,status
	PokeByte bank,5,r
	PokeByte bank,6,g
	PokeByte bank,7,b
	
	UpdateSomething(bank)
	
	Return bank
	
End Function
;----------------------------------------------------------------------------------------------------
;-- just a handy global function --------------------------------------------------------------------
;----------------------------------------------------------------------------------------------------
Function Limit(value,minvalue,maxvalue)
	If value<minvalue Return minvalue
	If value>maxvalue Return maxvalue
	Return value
End Function
 | 
| 
 | ||
| Very interesting | 
| 
 | ||
| LOoks a good way to make up for the lack of gadjets | 
| 
 | ||
| here's another example.. a scroll-panel Notice that found a dumb thingy while preparing this post.. I'm too lazy to fix it however.. :) For obvious reasons the scrollpanel needs to be as wide as the parent-panel.. so having an arguement stating the width of you scrollpanel would'n much useful when you can get the gadgetwidth of the parent panel to get that width ;) anyway (it's just an example, soon enough you should be making your own gadgets anyway), enjoy.. 
app=CreateWindow("",0,0,640,480)
; create 2 parent panels
panel1=CreatePanel(20,20,256,256,app)
panel2=CreatePanel(320,20,256,256,app)
; create the scrollpanels
scrollpanel1=CreateVScrollpanel(256,768,panel1,32,160,160,160)
scrollpanel2=CreateVScrollpanel(256,512,panel2,32,160,160,160)
; put some example crap on the scrollpanels
For t=0 To 10
	CreateButton(t,32,20+t*64,64,24,VScrollpanelPanel(scrollpanel1)) 
	CreateButton(t,32+t*5,20+t*32,64,24,VScrollpanelPanel(scrollpanel2)) 
Next
; main loop
quit=False
Repeat
	WaitEvent()
	
	If EventID()=$803 quit=True
	; if you don't include these, you can't scroll!	
	VScrollpanelEvents (scrollpanel1)
	VScrollpanelEvents (scrollpanel2)
	
Until quit
; clean-up
FreeBank scrollpanel1
FreeBank scrollpanel2
; bye!
End
; returns the actual panelhandle of the scrollpanel..
Function VScrollpanelPanel(bank)
	Return PeekInt(bank,4)
End Function
Function VScrollpanelEvents(bank)
	canvas=PeekInt(bank,8)
	
	If EventSource()=canvas
	
		If EventID()=$201 
			PokeByte bank,19,1 ; drag=true
			PokeShort bank,20,MouseY() ; start coord.
		EndIf
		
		If EventID()=$202
			PokeByte bank,19,0 ; drag=false
		EndIf
		
		If PeekByte(bank,19) ; drag ?
			If EventID()=$203
			
				y=MouseY()
				
				panel=PeekInt(bank,4)
				oldy=PeekShort(bank,20)
				
				ycoord=GadgetY(panel)+y-oldy
				ycoord=Limit(ycoord,-PeekShort(bank,14)+PeekShort(bank,22),0)
				
				SetGadgetShape panel,GadgetX(panel),ycoord,GadgetWidth(panel),GadgetHeight(panel)
				PokeShort bank,20,y
				
			EndIf
		EndIf
		
	EndIf
End Function
Function CreateVScrollpanel(width,height,parent,dragwidth,r,g,b)
	If width*height=0 Break"Incorrect dimensions!"
	If height<GadgetHeight(parent) Break"Panel height-bigger than parent-height!"
	If Not parent Break"Parent missing"
	If Not dragwidth Break"Dragbar zero"
	r=Limit(r,0,255)
	g=Limit(g,0,255)
	b=Limit(b,0,255)
	
	; adr	name		size
	; 00	ID			4 bytes    <- reserved for an optional 4-chars ID check! not used right now..
	; 04	panel		1 int (4 bytes)
	; 08	dragcanvas	1 Int (4 bytes)
	; 12	width		1 short (2 bytes)
	; 14	height		1 short (2 bytes)
	; 16	r			1 byte
	; 17	g			1 byte
	; 18	b			1 byte
	; 19	dragstatus	1 byte
	; 20	dragY		1 short (2 bytes)
	; 22	parntheight	1 short (2 bytes)
	bank=CreateBank(24)
	
	panel=CreatePanel(0,0,width,height,parent)
	SetPanelColor panel,r,g,b
	canvas=CreateCanvas(width-dragwidth,0,dragwidth,height,panel)
	SetCanvas canvas
		ClsColor r,g,b:Cls
		For y=2 To height-1 Step 4
			For x=2 To dragwidth-1 Step 4
				xo=(y Mod 8)/4
				Bcolor r*1.3,g*1.3,b*1.3
				Plot x+xo,y
				Bcolor r*0.7,g*0.7,b*0.7
				Plot x+xo+1,y+1
			Next
		Next
		Bcolor r*1.3,g*1.3,b*1.3
		Line 0,0,0,height-2
		Line 0,0,dragwidth-2,0
		
		Bcolor r*0.7,g*0.7,b*0.7
		Line dragwidth-1,1,dragwidth-1,height-2
		Line 1,height-1,dragwidth-2,height-1
		
	FlipCanvas canvas
	
	PokeInt bank,4,panel
	PokeInt bank,8,canvas
	PokeShort bank,12,width
	PokeShort bank,14,height
	PokeByte bank,16,r
	PokeByte bank,17,g
	PokeByte bank,18,b
	
	PokeShort bank,22,GadgetHeight (parent)
	
	Return bank
End Function
; misc. needed global functions.. some useful, some just for the lazy coder (SetCanvas) :)
Function Limit(value,minvalue,maxvalue)
	If value<minvalue Return minvalue
	If value>maxvalue Return maxvalue
	Return value
End Function
Function Break(s$)
	Notify s$
	End
End Function
Function Bcolor(r,g,b)
	r=Limit(r,0,255)
	g=Limit(g,0,255)
	b=Limit(b,0,255)
	Color r,g,b
End Function
Function SetCanvas(bla)
	SetBuffer CanvasBuffer(bla)
End Function
 | 
| 
 | ||
| That's really very useful. |