PDA

View Full Version : Prompt > Simple console demo of word whisperer



Petr Schreiber
10-07-2012, 16:28
Sometimes we are (read "I am") lazy to write long words, and the laziness can affect even console type scripts. So I tried to implement something similar to Google "whisperer".

How does it work
I created simple Prompt procedure, which takes as input:

prompt for user
array full off possible suggestions


The function returns the string once user hits the Return (Enter) key.

To be able to "guess" what user wants to type, I need to check what user does character by character - this is possible thanks to Console_Waitkey (Console_Read and Console_ReadLine return after press of Enter, no sooner).

Once I detect the user pressed down arrow, I check if there is an suggestion active, and if yes, I fill it for the (lazy :)) user.

How to test
To test the procedure, I prepaired little example. The suggestions are stored in array named ... suggestions. They possible words are (feel free to modify):


the
thin
turtle
terrific
thinbasic


When you start the program, just type the letter "t", and you will see it will immediately offer you the word "terrific" (as it is the first match in alphabetical order), as you type other letters, you get the other suggestions or none (if there is no match).

Feel free to play with it, modify, use as you need. The possible uses could be help with typing directory name or other cases, when input can be partially predicted. You just need to fill array of suggestions and pass it to the function, the rest should be done automagically by the "engine".

Example


'
' Smart Prompt Test
'
' version 1.0
' Petr Schreiber 2012
'

Uses "console"

String suggestions(5) = "the", "thin", "turtle", "terrific", "thinbasic"

String sRetVal = Prompt("Enter the keyword: ", suggestions)

PrintL "You wrote " + sRetVal
PrintL
PrintL "Press any key to quit"
WaitKey


Function Prompt(sQuestion As String, suggestions() As String ) As String

' -- Let's keep the suggestions sorted for faster search
Array Sort suggestions()

' -- Print the question first
Print sQuestion

' -- Set contrast color for user reply
Console_SetTextAttribute(%CONSOLE_FOREGROUND_BLUE | %CONSOLE_FOREGROUND_GREEN | %CONSOLE_FOREGROUND_RED | %CONSOLE_FOREGROUND_INTENSITY)

String sRetVal
String sChar, sSuggestion
Long xPos, yPos, j, found, offset

' -- Keep reading till user presses Return (aka Enter)
While sChar <> "RETURN"
' -- Store cursor position for later
xPos = Console_GetCursorX
yPos = Console_GetCursorY

' -- Read new characer
sChar = Grab$(Console_WaitKey(), "[", "]")

' -- If it is normal, just write it to terminal
If Len(sChar) = 1 Then
sRetVal += sChar
Print sChar

' -- If it is down key, user wants to fill in the suggestion
ElseIf sChar = "DOWN" Then
If Len(sSuggestion) Then
Console_SetCursorPosition(Len(sQuestion)+1, ypos+1)
Print sSuggestion
Console_SetCursorPosition(Len(sQuestion)+Len(sSuggestion)+1, ypos+1)

sRetVal = sSuggestion
End If

' -- Special handling for deleting
ElseIf sChar = "DELETE" Then

If xPos > Len(sQuestion) Then
Console_PrintAt(" ", xPos,ypos+1)

Console_SetCursorPosition(xpos, ypos)
sRetVal = LEFT$(sRetVal, Len(sRetVal)-1)
End If
End If

' -- Here we do the dynamic search (very suboptimal :)) for suggestions
' -- Only if user already entered something
If Len(sRetVal) Then

found = FALSE

' -- We search whole passed array
For j = LBound(suggestions) To UBound(suggestions)

' -- If the entered thing matches pattern of suggestion, it could be it!
If IsLike(suggestions(j), sRetVal+"*" , FALSE) Then

' -- Store suggestion for later use and print it on the screen
sSuggestion = suggestions(j)
offset = Len(sQuestion) + Len(sSuggestion)
Console_PrintAt($SPC(Len(sQuestion))+sSuggestion + $SPC(80-offset), 1,ypos+2)
found = TRUE
Exit For
End If

Next

' -- If nothing was found, then erase the suggestion line
If found = FALSE Then
Console_PrintAt($SPC(80), 1,ypos+2)
sSuggestion = ""
End If

Else
Console_PrintAt($SPC(80), 1,ypos+2)
sSuggestion = ""

End If

Wend

' -- Clean up after the suggester, if somehing was left on the screen to not waste one line
Console_PrintAt($SPC(80), 1,ypos+2)

' -- Force continuing on next line after question
PrintL

' -- Reset color back to normal
Console_SetTextAttribute(%CONSOLE_FOREGROUND_BLUE | %CONSOLE_FOREGROUND_GREEN | %CONSOLE_FOREGROUND_RED )

' -- Return the value
Return sRetVal

End Function


Petr

largo_winch
11-07-2012, 15:29
a) good example petr, I like it. do you're thinking it's possible to convert console example to ui (gui) style too?

b) I have a simple question to this listbox, why this doesn't work correct? bye, largo



' Empty GUI script created on 07-11-2012 10:42:28 by largo_winch

Uses "UI", "console"

' -- ID numbers of controls
Begin ControlID
%ButtonClose = 1001
%tmyListWords
%tMyInput
%myLabel
End ControlID

Function TBMain() As Long
Dim hDlg As DWord

Dialog New 0, "word_find_list 01",-1,-1, 320, 250, _
%WS_POPUP Or _
%WS_VISIBLE Or _
%WS_CLIPCHILDREN Or _
%WS_CAPTION Or _
%WS_SYSMENU Or _
%WS_MAXIMIZEBOX Or _
%WS_MINIMIZEBOX, _
0 To hDlg

Control Add Button, hDlg, %ButtonClose, "Click to kill", 230, 210, 50, 18
'Control Add Label, hDlg, %myLabel, "type in a word",240,50,90,20
Dialog Show Modal hDlg Call cbDialog
End Function

CallBack Function cbDialog() As Long
Local hDlg As Long, hText1 As Long, sMyContent As Long, sMyNewContent As String, thisposition As Long
'String suggestions(5) = "the", "thin", "turtle", "terrific", "thinbasic"

Select Case CBMSG

Case %WM_INITDIALOG
Dim vWordList(7) As String
vWordList(1) = "fun"
vWordList(2) = "further"
vWordList(3) = "father"
vWordList(4) = "fork"
vWordList(5) = "foreign"
vWordList(6) = "foster"
vWordList(7) = "friend"

Control Add LISTBOX, CBHNDL,%tMyListWords, vWordList(), 5,25,220,280, %WS_VSCROLL Or %LBS_NOINTEGRALHEIGHT,%WS_EX_CLIENTEDGE
Control Add Textbox CBHNDL, %tMyInput , "", 240, 25, 60, 24 ', %ES_AUTOHSCROLL Or %ES_LEFT Or %WS_BORDER Or %WS_TABSTOP Or %ES_MULTILINE Or %ES_WANTRETURN Or %WS_VSCROLL,,

Case %WM_COMMAND
If CBWPARAM = %ButtonClose Then Dialog End CBHNDL
Select Case CBCTL

Case %tMyListWords
Select Case CBCTLMSG
Case %LBN_SELCHANGE

'------------------------- ??? -------------------------- >
LISTBOX Get Text CBHNDL, %tMyListWords To sMyContent
Control Set Text CBHNDL, %tMyInput, sMyContent
' result always "0" instead of a string ???
'------------------------- ??? -------------------------- >
MsgBox 0, sMyContent
Case %LBN_DBLCLK
LISTBOX Get Text CBHNDL, %tMyListwords To sMyContent
Control Append Text CBHNDL, %tMyInput, "(DblClick " & sMyContent & ")"

End Select
End Select

Case %WM_DESTROY
End Select
End Function

Petr Schreiber
11-07-2012, 15:50
Hi Frank,

in GUI world, the most simple for this task is to use combobox - it can has predefined values you can pick from.
Try the example below - type in "thinb" and press down arrow. It will fill in ThinBASIC for you.

You could also replace %CBS_SIMPLE with %CBS_DROPDOWN for more decent effect:


'
' Simple word completion possible thanks to Combobox control
'

Uses "UI"

' -- ID numbers of controls
Begin ControlID
%cbInput
%bClose
End ControlID

Begin Const
%MAIN_WIDTH = 320
%MAIN_HEIGHT = 150
End Const

' -- Create dialog here
Function TBMain()
Local hDlg As DWord

Dialog New Pixels, 0, "Word whisperer",-1,-1, %MAIN_WIDTH, %MAIN_HEIGHT, _
%WS_POPUP Or %WS_VISIBLE Or %WS_CAPTION Or %WS_SYSMENU Or %WS_MINIMIZEBOX To hDlg

' -- List of possible words
String suggestions(5) = "the", "thin", "turtle", "terrific", "thinbasic"

' -- Combobox with special styles:
' * CBS_SIMPLE - makes all items visible immediately
' * CBS_SORT - enables automagical sort
Control Add COMBOBOX, hDlg, %bClose, suggestions, 5, 5, %MAIN_WIDTH-10, 100, %CBS_SIMPLE | %CBS_SORT

Control Add Button, hDlg, %bClose, "Click to close", %MAIN_WIDTH-105, %MAIN_HEIGHT-30, 100, 25, Call cbCloseButton

Control Set Focus hDlg, %bClose

Dialog Show Modal hDlg, Call cbDialog

End Function

' -- Callback for dialog
CallBack Function cbDialog()

' -- Test for messages
Select Case CBMSG

Case %WM_INITDIALOG
' -- Put code to be executed after dialog creation here

Case %WM_COMMAND
' -- You can handle controls here

Case %WM_CLOSE
' -- Put code to be executed before dialog end here

End Select

End Function

' -- Callback for close button
CallBack Function cbCloseButton()

If CBMSG = %WM_COMMAND Then
If CBCTLMSG = %BN_CLICKED Then
' -- Closes the dialog
Dialog End CBHNDL
End If
End If

End Function



Petr

largo_winch
11-07-2012, 19:13
a) sorry petr, but my name is still largo :p, my uncle's name is frank that's an important difference! we're living in nearby of ca. 32 kilometres ;) I am sitting in an internet cafe it's using by more than hundred people all day long there.

b) thank you petr for your example, but what was wrong with my shown example (listbox send "0" to textbox?) above? do you have test it?

bye, largo

Petr Schreiber
11-07-2012, 21:59
Hi Largo,

my apologies - you and your uncle have very similar way of writing, so I often forget who am I talking to, I will focus more next time :oops:

I looked at your example, the problem was simple - on the top of cbDialog you have:


Local hDlg As Long, hText1 As Long, sMyContent As long, sMyNewContent As String, thisposition As Long

and then later you do:


LISTBOX Get Text CBHNDL, %tMyListWords To sMyContent
Control Set Text CBHNDL, %tMyInput, sMyContent


... so - you have sMyContent As long, that is, number and try to use it to store text. Simply changing it to the:


sMyContent As String


... fixed your problem. I hope it helps.


Petr