Self-contained find dialog

BlitzMax Forums/BlitzMax GUI Programming/Self-contained find dialog

This code will enable a Windows Notepad-like Find dialog on any textarea gadget.

Usage:

Import "Find.bmx"
GADGET_MENU_FIND=CreateMenu("Find",0,menu)
CreateFindWindow(MainWindow:TGadget,TextArea:TGadget)

That's it!

Strict

Import brl.maxgui

Private

Global FindWindow:TGadget
Global GADGET_FIND_TEXT:TGadget
Global GADGET_FIND_OK:TGadget
Global GADGET_FIND_CANCEL:TGadget
Global GADGET_FIND_UP:TGadget
Global GADGET_FIND_DOWN:TGadget
Global GADGET_FIND_MATCHCASE:TGadget

Public

Global GADGET_MENU_FIND:TGadget
Global GADGET_FIND_TEXTAREA:TGadget

Function CreateFindWindow(group:TGadget,textarea:TGadget)
	Local panel:TGadget
	Local flags
	flags=WINDOW_TITLEBAR|WINDOW_HIDDEN'|WINDOW_CENTER|WINDOW_DIALOG
	FindWindow=CreateWindow("Find",200,200,360,133,group,flags)
	CreateLabel("Find what:",10,11,60,16,FindWindow)
	GADGET_FIND_TEXT=CreateTextField(71,11,192,20,FindWindow)
	GADGET_FIND_OK=CreateButton("Find Next",274-1,10,73+2,21+2,FindWindow,BUTTON_OK)
	GADGET_FIND_CANCEL=CreateButton("Cancel",274-1,33+2,73+2,21+2,FindWindow,BUTTON_CANCEL)
	GADGET_FIND_MATCHCASE=CreateButton("Match case",7,71,80,16,FindWindow,BUTTON_CHECKBOX)
	DisableGadget GADGET_FIND_OK
	panel=CreatePanel(160,48,102,44,FindWindow,PANEL_GROUP,"Direction")
	GADGET_FIND_UP=CreateButton("Up",5,7,35,16,panel,BUTTON_RADIO)
	GADGET_FIND_DOWN=CreateButton("Down",46,7,46,16,panel,BUTTON_RADIO)
	SetButtonState GADGET_FIND_DOWN,1
	GADGET_FIND_TEXTAREA=textarea
	AddHook EmitEventHook,FindWindowHook
EndFunction

Function ReverseString$(s$)
	Local n
	Local rs$
	For n=0 To s.length-1
		rs:+Chr(s[s.length-1-n])
	Next
	Return rs
EndFunction

Function FindWindowHook:Object(id:Int,data:Object,context:Object)
	Global LastActiveGadget:TGadget
	Local text$,p,searchstring$
	
	If data=Null Return Null
	Local event:TEvent=TEvent(data)
	Select event.id
		
		Case EVENT_GADGETACTION
			Select event.source
			
				Case GADGET_FIND_OK
					text=TextAreaText(GADGET_FIND_TEXTAREA)
					If Not ButtonState(GADGET_FIND_MATCHCASE) text=Lower(text)
					p=TextAreaCursor(GADGET_FIND_TEXTAREA)
					searchstring=TextFieldText(GADGET_FIND_TEXT)
					If Not ButtonState(GADGET_FIND_MATCHCASE) searchstring=Lower(searchstring)
					If ButtonState(GADGET_FIND_UP)
						text=ReverseString(text)
						searchstring=reversestring(searchstring)
						p=text.length-p
					EndIf
					p=text.find(searchstring,p+1)
					If p>-1
						If ButtonState(GADGET_FIND_UP)
							p=text.length-p
							p=p-searchstring.length
						EndIf
						SelectTextAreaText GADGET_FIND_TEXTAREA,p,searchstring.length
						ActivateGadget GADGET_FIND_OK
					Else
						Notify "Cannot find ~q"+TextFieldText(GADGET_FIND_TEXT)+"~q"
					EndIf
					
				Case GADGET_FIND_TEXT
					If TextFieldText(GADGET_FIND_TEXT)=""
						DisableGadget GADGET_FIND_OK
					Else
						EnableGadget GADGET_FIND_OK
					EndIf
					
				Case GADGET_FIND_CANCEL
					EmitEvent CreateEvent(EVENT_WINDOWCLOSE,FindWindow)
			
			EndSelect
		
		Case EVENT_MENUACTION
			Select event.source
				Case GADGET_MENU_FIND
					LastActiveGadget=ActiveGadget()
					ShowGadget FindWindow
					ActivateGadget GADGET_FIND_OK
					ActivateGadget GADGET_FIND_TEXT
					
			EndSelect

		Case EVENT_WINDOWCLOSE
			Select event.source
				
				Case FindWindow
					If LastActiveGadget
						ActivateGadget LastActiveGadget
					Else
						ActivateGadget GadgetGroup(FindWindow)
					EndIf
					HideGadget FindWindow
					
			EndSelect
	EndSelect
	Return data
EndFunction


This is an updated version that will search up & down. I also added a GADGET_MENU_FINDNEXT menu item. Just create it and the application will handle everything, including enabling and disabling the menu. You should disable the GADGET_MENU_FINDNEXT menu item when it is created.

Strict

Import brl.maxgui

Private

Global FindWindow:TGadget
Global GADGET_FIND_TEXT:TGadget
Global GADGET_FIND_OK:TGadget
Global GADGET_FIND_CANCEL:TGadget
Global GADGET_FIND_UP:TGadget
Global GADGET_FIND_DOWN:TGadget
Global GADGET_FIND_MATCHCASE:TGadget

Public

Global GADGET_MENU_FIND:TGadget
Global GADGET_MENU_FINDNEXT:TGadget
Global GADGET_FIND_TEXTAREA:TGadget

Function CreateFindWindow(group:TGadget,textarea:TGadget)
	Local panel:TGadget
	Local flags
	flags=WINDOW_TITLEBAR|WINDOW_HIDDEN'|WINDOW_CENTER|WINDOW_DIALOG
	FindWindow=CreateWindow("Find",200,200,360,133,group,flags)
	CreateLabel("Find what:",10,11,60,16,FindWindow)
	GADGET_FIND_TEXT=CreateTextField(71,11,192,20,FindWindow)
	GADGET_FIND_OK=CreateButton("Find Next",274-1,10,73+2,21+2,FindWindow,BUTTON_OK)
	GADGET_FIND_CANCEL=CreateButton("Cancel",274-1,33+2,73+2,21+2,FindWindow,BUTTON_CANCEL)
	GADGET_FIND_MATCHCASE=CreateButton("Match case",7,71,80,16,FindWindow,BUTTON_CHECKBOX)
	DisableGadget GADGET_FIND_OK
	panel=CreatePanel(160,48,102,44,FindWindow,PANEL_GROUP,"Direction")
	GADGET_FIND_UP=CreateButton("Up",5,7,35,16,panel,BUTTON_RADIO)
	GADGET_FIND_DOWN=CreateButton("Down",46,7,46,16,panel,BUTTON_RADIO)
	SetButtonState GADGET_FIND_DOWN,1
	GADGET_FIND_TEXTAREA=textarea
	AddHook EmitEventHook,FindWindowHook
EndFunction

Private

Function Find()
	Local text$,p,searchstring$
	text=TextAreaText(GADGET_FIND_TEXTAREA)
	If text="" Return
	If Not ButtonState(GADGET_FIND_MATCHCASE) text=Lower(text)
	p=TextAreaCursor(GADGET_FIND_TEXTAREA)
	searchstring=TextFieldText(GADGET_FIND_TEXT)
	If Not ButtonState(GADGET_FIND_MATCHCASE) searchstring=Lower(searchstring)
	If ButtonState(GADGET_FIND_UP)
		text=ReverseString(text)
		searchstring=reversestring(searchstring)
		p=text.length-p
	EndIf
	p=text.find(searchstring,p+1)
	If p>-1
		If ButtonState(GADGET_FIND_UP)
			p=text.length-p
			p=p-searchstring.length
		EndIf
		SelectTextAreaText GADGET_FIND_TEXTAREA,p,searchstring.length
	Else
		Notify "Cannot find ~q"+TextFieldText(GADGET_FIND_TEXT)+"~q"
	EndIf
	
	Function ReverseString$(s$)
		Local n
		Local rs$
		For n=0 To s.length-1
			rs:+Chr(s[s.length-1-n])
		Next
		Return rs
	EndFunction
	
EndFunction

Function FindWindowHook:Object(id:Int,data:Object,context:Object)
	Global LastActiveGadget:TGadget
	If data=Null Return Null
	Local event:TEvent=TEvent(data)
	Select event.id
		
		Case EVENT_GADGETACTION
			Select event.source

				Case GADGET_FIND_OK
					Find()
					ActivateGadget GADGET_FIND_OK
					
				Case GADGET_FIND_TEXT
					If TextFieldText(GADGET_FIND_TEXT)=""
						DisableGadget GADGET_FIND_OK
						If GADGET_MENU_FINDNEXT
							DisableGadget GADGET_MENU_FINDNEXT
							UpdateWindowMenu GadgetGroup(FindWindow)
						EndIf
					Else
						EnableGadget GADGET_FIND_OK
						If GADGET_MENU_FINDNEXT
							EnableGadget GADGET_MENU_FINDNEXT
							UpdateWindowMenu GadgetGroup(FindWindow)
						EndIf
					EndIf
					
				Case GADGET_FIND_CANCEL
					EmitEvent CreateEvent(EVENT_WINDOWCLOSE,FindWindow)
			
			EndSelect
		
		Case EVENT_MENUACTION
			Select event.source
				Case GADGET_MENU_FIND
					LastActiveGadget=ActiveGadget()
					ShowGadget FindWindow
					ActivateGadget GADGET_FIND_OK
					ActivateGadget GADGET_FIND_TEXT
				Case GADGET_MENU_FINDNEXT
					Find()
				
			EndSelect

		Case EVENT_WINDOWCLOSE
			Select event.source
				
				Case FindWindow
					If LastActiveGadget
						ActivateGadget LastActiveGadget
					Else
						ActivateGadget GadgetGroup(FindWindow)
					EndIf
					HideGadget FindWindow
					
			EndSelect
	EndSelect
	Return data	
EndFunction

Public


looks good!
could you (or someone else) code that also for blitzplus ?