MaxGUI: create photoshop like buttons...

BlitzMax Forums/BlitzMax Programming/MaxGUI: create photoshop like buttons...

Hello,

I'm looking at the various button types vailable in MaxGui, and I don't seem to find what I need.
I'm trying to make a 2D tool and I need to have a panel of tools buttons similar to those in Photoshop etc. So I need the pressed button to stay pressed in order to show what tool is currently selected.

Any idea how I can achieve that ?

Thank you very much,
Nino

For something identical to Photosoup create your own button gadget based on an image. If you really want it identical then make a grey version of a loaded color image, and show the colored one case the button is pressed and grey when the button is not pressed.

Thanks !
Now I have to look hjow to make image-based button gadgets :)

Maybe I could cook something up.. I've a similar button made already but I have to adapt things a bit to have it more or less like photosoup..

If that could save me some headache, please be my guest and thank you so much ! :)

If it's easy to catch then don't bother but thank you anyway.

Nino

In fact yes, please, do something :)

[Warcraft2peasant]Job's doneeee[/Warcraft2peasant]

have a moment please.. I'll put testimages on the 'net..

grab these images to run the example






SuperStrict

Const EVENT_IMAGEBUTTONCLICKED:Int=$13370666  ' or any other, less l33t-evil, number :P

Type TImagebutton	' by CS_TBL

	Field canvas:TGadget
	Field parent:TGadget
	
	Field state:Int
	Field hoover:Int
	
	Field image:TImage
	Field grey:TImage
	
	Field hooverintensity:Int=24
	Field newevent:TEvent=New TEvent
	
	Function eventhook:Object(id:Int,data:Object,context:Object)
		If Timagebutton(context) Timagebutton(context).ev TEvent(data);Return data	
	EndFunction
	
	Method New()
		AddHook EmitEventHook,eventhook,Self
	End Method
	
	Method Free()
		RemoveHook EmitEventHook,eventhook
		GCCollect()
	End Method
	
	Method MakeGrey()
		Local r:Int,g:Int,b:Int,c:Int	
		Local x:Int,y:Int
		grey=CreateImage(ImageWidth(image),ImageHeight(image))
		
		Local pm:TPixmap=LockImage(image)
		Local pm2:TPixmap=LockImage(grey)
			For y=0 To ImageHeight(image)-1
				For x=0 To ImageWidth(image)-1
					c=ReadPixel(pm,x,y)
					r=c&255
					g=(c/256)&255
					b=(c/65536)&255
					c=(r+g+b)/3
					WritePixel pm2,x,y,c+256*c+65536*c|$ff000000
				Next
			Next
		UnlockImage image
		UnlockImage grey
	End Method
	
	Method ev(event:TEvent)
		If event.source=canvas
			If event.id=EVENT_GADGETPAINT update
			
			If event.id=EVENT_MOUSEENTER
				SetPointer POINTER_HAND		' <- comment out all SetPointer lines if you don't want changing cursors
				ActivateGadget canvas
				hoover=1
				update
				
			EndIf
			
			If event.id=EVENT_MOUSELEAVE
				SetPointer POINTER_DEFAULT
				ActivateGadget parent
				hoover=0
				update
			EndIf
			
			If event.id=EVENT_MOUSEDOWN
				Clickbutton event.data
			EndIf
			
			If event.id=EVENT_KEYDOWN
				If event.data=90 ' Z
					Clickbutton 1
				EndIf
				If event.data=88 ' X
					Clickbutton 2
				EndIf
			EndIf
		EndIf
		
	End Method
	
	Method Clickbutton(data:Int=1)
		If data=1
			newevent.data=1
		EndIf
		If data=2
			newevent.data=2
		EndIf
		state:+1
		state:Mod 2
		update
		
		newevent.source=Self
		newevent.id=EVENT_IMAGEBUTTONCLICKED
		
		EmitEvent newevent	
	End Method
	
	Method update()
		SetGraphics CanvasGraphics(canvas)
			SetClsColor 0,0,0;Cls
			If image
				SetBlend MASKBLEND
				SetColor 255,255,255
				
				If state
					DrawImage image,0,0
				Else
					DrawImage grey,0,0
				EndIf
				
				If hoover
					SetColor hooverintensity,hooverintensity,hooverintensity
					SetBlend LIGHTBLEND				
					DrawRect 0,0,GadgetWidth(canvas),GadgetHeight(canvas)
				EndIf
				SetBlend MASKBLEND
			EndIf
		Flip
	End Method
	
	Method SetState(st:Int)
		state=st
		update
	End Method
	
	Method GetState:Int()
		Return state
	End Method
	
	Method SetIntensity(i:Int)
		hooverintensity=i
	End Method
End Type

Function CreateImagebutton:TImagebutton(x:Int,y:Int,image:TImage,parent:TGadget,state:Int=0)
	If image=Null RuntimeError "no image given"
	If parent=Null RuntimeError "no parent given"
	
	Local a:TImagebutton=New TImagebutton
	a.image=image
	a.MakeGrey	
	a.canvas=CreateCanvas(x,y,ImageWidth(image),ImageHeight(image),parent)
	a.parent=parent
	a.state=state
	Return a
End Function

Type TImagebuttongroup

	Field list:TImagebutton[]
	Field amount:Int=0
	Field newevent:TEvent=New TEvent
	
	Function eventhook:Object(id:Int,data:Object,context:Object)
		If TImagebuttongroup(context) TImagebuttongroup(context).ev TEvent(data);Return data	
	EndFunction
	
	Method New()
		AddHook EmitEventHook,eventhook,Self
	End Method
	
	Method Free()
		RemoveHook EmitEventHook,eventhook
		GCCollect()
	End Method
	
	Method ev(event:TEvent)
		If event.id=EVENT_IMAGEBUTTONCLICKED
			Local t:Int
			Local tt:Int
			For t=0 To amount-1
				If event.source=list[t]
					For tt=0 To amount-1
						list[tt].SetState 0
					Next
					list[t].SetState 1
				EndIf
			Next
		EndIf
	End Method
	
	Method Add(t:TImagebutton)
		amount:+1
		list=list[..amount]
		list[amount-1]=New TImagebutton
		list[amount-1]=t
	End Method
End Type









Rem

 EXAMPLE!

EndRem










Local window:TGadget=CreateWindow(".",0,0,640,480)

' 4 images
Local im1:TImage=LoadImage("brush.png")
Local im2:TImage=LoadImage("cut.png")
Local im3:TImage=LoadImage("paint.png")
Local im4:TImage=LoadImage("pencil.png")

' 4 buttons that can all be switched on and off
Local MyButton1:TImagebutton=CreateImagebutton(32,32,im1,window,0)
Local MyButton2:TImagebutton=CreateImagebutton(32,80,im2,window,0)
Local MyButton3:TImagebutton=CreateImagebutton(96,32,im3,window,0)
Local MyButton4:TImagebutton=CreateImagebutton(96,80,im4,window,0)

' same stuff again..
Local MyButton5:TImagebutton=CreateImagebutton(232,32,im1,window,1)
Local MyButton6:TImagebutton=CreateImagebutton(232,80,im2,window,0)
Local MyButton7:TImagebutton=CreateImagebutton(232,128,im3,window,0)
Local MyButton8:TImagebutton=CreateImagebutton(232,176,im4,window,0)

' ..but now tucked away into a group so they act as radiobuttons (only one is active)
Local group:TImagebuttongroup=New TImagebuttongroup
group.Add MyButton5
group.Add MyButton6
group.Add MyButton7
group.Add MyButton8

Repeat
	WaitEvent()
	
	If EventID()=EVENT_WINDOWCLOSE End
	
	If EventID()=EVENT_IMAGEBUTTONCLICKED
	
		DebugLog Mid("leftclicked rightclicked",1+(EventData()-1)*12,12)
		
		Select EventSource()
			Case MyButton1,MyButton5
				DebugLog "brush!"
			Case MyButton2,MyButton6
				DebugLog "cut!"
			Case MyButton3,MyButton7
				DebugLog "paint!"
			Case MyButton4,MyButton8
				DebugLog "pencil!"
		End Select

	EndIf
Forever


I'll add it to the archives I think.. I've seen oodles and oodles of requests for imagebuttons already..

Trivia! [Z] and [X] on a button double-up as leftclick and rightclick, nice for ppl with a tablet/pen with crappy buttons on it.. or for ppl with finger-RSI. :P

That said: you can either leftclick or rightclick! (in event.data or EventData())

Enjoy!

Dude! Thanks! This is a great example!

well, i'm trying to convert this, http://www.blitzbasic.com/Community/posts.php?topic=46784 ,to Max but it isn't working too well.
Strict

Import PUB.Win32

'Must load images with the DYNAMICIMAGE flag
AutoImageFlags(MASKEDIMAGE | FILTEREDIMAGE | DYNAMICIMAGE)

Local window:TGadget=CreateWindow("Button Image Test",0,0,640,480,Null,WINDOW_TITLEBAR)

Local testbutton:TGadget=CreateButton("Click Here",10,10,100,50,window)

Repeat
	WaitEvent()
	Select EventID()
		Case EVENT_WINDOWCLOSE
			End
		Case EVENT_GADGETACTION
			Select EventSource()
				Case testbutton
					Local file$=RequestFile("Select image load","Image Files:bmp,jpg,png")
					Local image:TImage=LoadImage(file$,DYNAMICIMAGE)
					If image 					
						If Not SetButtonImage(testbutton,image,True) Notify "Failed to set button's image"
					Else
						Notify "Failed to load image"
					EndIf
			End Select
	End Select	
Forever

?Win32
Extern "win32"
	Function SetWindowLong(hWnd ,nIndex,lNewLong )= "SetWindowLongA@12"
	Function GetModuleHandle:Int(lMod)="GetModuleHandleA@4"
	Function GetWindowLong(hWnd ,nIndex)="GetWindowLongA@8"
	Function CreateBitmap(nWidth,nHeight,cPlanes,cBitsPerPixel,lpvBits:Byte Ptr)
	Function LoadBitmap(hInstance,lpBitmapName:Byte Ptr)="LoadBitmapW@8"
	Function GetBitmapDimensionEx(hBitmap,lpDimension:Byte Ptr)
	Function DeleteObject(obj)	
End Extern

Const BM_SETIMAGE=247
Const IMAGE_BITMAP=0
Const IMAGE_ICON=1
Const BS_BITMAP=128
Const GWL_STYLE=-16
Const LR_DEFAULTSIZE=64
Const LR_LOADFROMFILE=16
Const LR_SHARED=32768
?

Rem
bbdoc: Set the image of a TWin32Gadget
returns: #brl.blitz.True if successful, #brl.blitz.False if not.
End Rem
Function SetButtonImage(button:TGadget,image:TImage,resize=True)
	?MacOS
		Return False
	?Linux
		Return False
	?Win32
		Local hbutton=QueryGadget(button,QUERY_HWND)
		Local flags=GetWindowLong(hbutton,GWL_STYLE)
		If image<>Null
			If flags&BS_BITMAP=0 SetWindowLong hbutton,GWL_STYLE,flags|BS_BITMAP
		Else
			If flags&BS_BITMAP SetWindowLong hbutton,GWL_STYLE,flags-BS_BITMAP
			Return
		EndIf
		Local w=ImageWidth(image)
		Local h=ImageHeight(image)
		Local ibuffer:TPixmap=LockImage(image,0,True,True)
		Local pixels:TBank=CreateBank(w*h*4)
		For Local y=0 To h-1
			For Local x=0 To w-1
				PokeInt pixels,4*((y*w)+x)+0,ReadPixel(ibuffer,x,y)
			Next
		Next
		UnlockImage image
		Local i=CreateBitmap(w,h,1,32,pixels)
		If Not i Return
		If resize
			SetGadgetShape button,GadgetX(button),GadgetY(button),w,h
		EndIf
		Local oldimage=SendMessageA(hbutton,BM_SETIMAGE,IMAGE_BITMAP,i)
		If oldimage DeleteObject(oldimage)
		Return True
	?
End Function


CS_TBL:

Thanks dude, that seem to work great, exactly as I expect it. the only thing is that I guess I'm too beginner to really understand what you're doing, so commenting your code a little bit would be welcome, if don't mind. :)

I could.. but do you really need to know how the internal code works? I figure it's like use & go .. without worries about the how & why ..