I'm working on an old-style text game and I'm trying to use EditorGadgets to build a command interface. Everything works great, EXCEPT... When the command display window "fills-up" the text starts populating below what is visible and doesn't auto-scroll to the bottom. (The text is populated via code from another input editor, or from code behind-the-scenes.)
My problem is that I have found no way in SB to force the cursor to the end/bottom of the text or to force the scrollbar for the gadget to the 100% bottom position, but apparently this should be pretty easy using inline js. (Unfortunately, I am no js expert and even less-so using inline js in SB.)
I've trimmed down my code to just the editor portion and setup some sample text that gives both further explanation of the problem, and a command to force 'lorem ipsum' text to reproduce the issue. (Just type 'intro' and hit [enter] to see. Any other one word entries will result in a successful command response. All other non-one-word entries will show invalid command errors.)
This code runs stand-alone, so hopefully the issue will be clear and the solution quick and simple. Thanks in advance for your assistance!
Code: Select all
EnableExplicit
;Windows
#MainBackgroundWindow = 0
;Gadgets
#UserTextConsole = 0
#UserInputEditor = 1
#UserEnterButton = 2
#MainWindowTimer = 3
;Styles/Colors for Gadgets
#UserInputEditorBGColor = $2A2A2A
#UserInputEditorTextColor = $BACCBA
#UserTextConsoleBGColor = $313131
#UserTextConsoleTextColor = $00CC00
;Input Editor MaxLength
#UserInputEditorMaxLength = 100
#UserInputRegExID = 0
#UserInputRegExDefault = "[a-zA-Z0-9]+"
Global gUserInputRegEx$ = #UserInputRegExDefault ;Use gUserInputRegEx$ to manage current RegEx, use #UserInputRegExDefault to set gUserInputRegEx$ near top to default
#UserInputHistoryArraySize = 15 ;16 elements: 0-15
#UserInputHistory_Append = 0
#UserInputHistory_ShowPrevious = 1
#UserInputHistory_ShowNext = 2
#DefaultInvalidUserInputErrorMsg = "Invalid input. Nothing To do."
#IntroductionResponse$ = "I'm trying to solve the issue where once text scrolls lower down on the screen than can phsically fit (on-screen visibly) in the editor, it does not scroll to the very bottom to display the last line. So, what I am looking for is some inline js to force this editor to show the last line available. (Scrollbar to 100%??? Force cursor to last character's position?) Whatever can be done to just always force the last text entered to be visible upon refresh would be great! Hoping some quick and simple ine js will do ths trick, but never did that in SB, nor am I a JS guy...Thanks in advance!" + #LF$ + #LF$+ "This is an Interface test only. (Typing any valid single-word entered will return successful. Any longer phrases will result in an invalid command response. There is no advanced logic included - underlying code removed.)" + #LF$ + #LF$ + "Long 'lorem ipsum' text follows to push the screen down. If you want to add more 'lorem ipsum' text, just type 'intro' and hit [enter]. This message will be repeated." + #LF$ + #LF$ + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut condimentum cursus blandit. Nullam consectetur, ipsum sed sodales elementum, lacus orci elementum augue, a sollicitudin diam tellus in libero. Donec vehicula neque turpis, vel facilisis orci dignissim vitae. Vivamus tempor accumsan porta. Mauris molestie sagittis sapien at sollicitudin. Morbi vehicula in justo eu luctus. Integer eu eros nec sapien tempus maximus ut eu purus. Suspendisse ut felis ipsum. Aliquam ligula lectus, feugiat a porta a, finibus sit amet erat. Nullam pulvinar mattis accumsan. Fusce ac rutrum nisl. Maecenas volutpat gravida nisl, et maximus dolor varius eget. Nulla et vehicula ligula. Curabitur tempor risus eu tortor efficitur, ac faucibus dui porttitor. Aliquam erat volutpat. Quisque eu dolor sagittis, tempus purus a, suscipit nisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut condimentum cursus blandit. Nullam consectetur, ipsum sed sodales elementum, lacus orci elementum augue, a sollicitudin diam tellus in libero. Donec vehicula neque turpis, vel facilisis orci dignissim vitae. Vivamus tempor accumsan porta. Mauris molestie sagittis sapien at sollicitudin. Morbi vehicula in justo eu luctus. Integer eu eros nec sapien tempus maximus ut eu purus. Suspendisse ut felis ipsum. Aliquam ligula lectus, feugiat a porta a, finibus sit amet erat. Nullam pulvinar mattis accumsan. Fusce ac rutrum nisl. Maecenas volutpat gravida nisl, et maximus dolor varius eget. Nulla et vehicula ligula. Curabitur tempor risus eu tortor efficitur, ac faucibus dui porttitor. Aliquam erat volutpat. Quisque eu dolor sagittis, tempus purus a, suscipit nisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut condimentum cursus blandit. Nullam consectetur, ipsum sed sodales elementum, lacus orci elementum augue, a sollicitudin diam tellus in libero. Donec vehicula neque turpis, vel facilisis orci dignissim vitae. Vivamus tempor accumsan porta. Mauris molestie sagittis sapien at sollicitudin. Morbi vehicula in justo eu luctus. Integer eu eros nec sapien tempus maximus ut eu purus. Suspendisse ut felis ipsum. Aliquam ligula lectus, feugiat a porta a, finibus sit amet erat. Nullam pulvinar mattis accumsan. Fusce ac rutrum nisl. Maecenas volutpat gravida nisl, et maximus dolor varius eget. Nulla et vehicula ligula. Curabitur tempor risus eu tortor efficitur, ac faucibus dui porttitor. Aliquam erat volutpat. Quisque eu dolor sagittis, tempus purus a, suscipit nisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut condimentum cursus blandit. Nullam consectetur, ipsum sed sodales elementum, lacus orci elementum augue, a sollicitudin diam tellus in libero. Donec vehicula neque turpis, vel facilisis orci dignissim vitae. Vivamus tempor accumsan porta. Mauris molestie sagittis sapien at sollicitudin. Morbi vehicula in justo eu luctus. Integer eu eros nec sapien tempus maximus ut eu purus. Suspendisse ut felis ipsum. Aliquam ligula lectus, feugiat a porta a, finibus sit amet erat. Nullam pulvinar mattis accumsan. Fusce ac rutrum nisl. Maecenas volutpat gravida nisl, et maximus dolor varius eget. Nulla et vehicula ligula. Curabitur tempor risus eu tortor efficitur, ac faucibus dui porttitor. Aliquam erat volutpat. Quisque eu dolor sagittis, tempus purus a, suscipit nisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut condimentum cursus blandit. Nullam consectetur, ipsum sed sodales elementum, lacus orci elementum augue, a sollicitudin diam tellus in libero. Donec vehicula neque turpis, vel facilisis orci dignissim vitae. Vivamus tempor accumsan porta. Mauris molestie sagittis sapien at sollicitudin. Morbi vehicula in justo eu luctus. Integer eu eros nec sapien tempus maximus ut eu purus. Suspendisse ut felis ipsum. Aliquam ligula lectus, feugiat a porta a, finibus sit amet erat. Nullam pulvinar mattis accumsan. Fusce ac rutrum nisl. Maecenas volutpat gravida nisl, et maximus dolor varius eget. Nulla et vehicula ligula. Curabitur tempor risus eu tortor efficitur, ac faucibus dui porttitor. Aliquam erat volutpat. Quisque eu dolor sagittis, tempus purus a, suscipit nisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut condimentum cursus blandit. Nullam consectetur, ipsum sed sodales elementum, lacus orci elementum augue, a sollicitudin diam tellus in libero. Donec vehicula neque turpis, vel facilisis orci dignissim vitae. Vivamus tempor accumsan porta. Mauris molestie sagittis sapien at sollicitudin. Morbi vehicula in justo eu luctus. Integer eu eros nec sapien tempus maximus ut eu purus. Suspendisse ut felis ipsum. Aliquam ligula lectus, feugiat a porta a, finibus sit amet erat. Nullam pulvinar mattis accumsan. Fusce ac rutrum nisl. Maecenas volutpat gravida nisl, et maximus dolor varius eget. Nulla et vehicula ligula. Curabitur tempor risus eu tortor efficitur, ac faucibus dui porttitor. Aliquam erat volutpat. Quisque eu dolor sagittis, tempus purus a, suscipit nisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut condimentum cursus blandit. Nullam consectetur, ipsum sed sodales elementum, lacus orci elementum augue, a sollicitudin diam tellus in libero. Donec vehicula neque turpis, vel facilisis orci dignissim vitae. Vivamus tempor accumsan porta. Mauris molestie sagittis sapien at sollicitudin. Morbi vehicula in justo eu luctus. Integer eu eros nec sapien tempus maximus ut eu purus. Suspendisse ut felis ipsum. Aliquam ligula lectus, feugiat a porta a, finibus sit amet erat. Nullam pulvinar mattis accumsan. Fusce ac rutrum nisl. Maecenas volutpat gravida nisl, et maximus dolor varius eget. Nulla et vehicula ligula. Curabitur tempor risus eu tortor efficitur, ac faucibus dui porttitor. Aliquam erat volutpat. Quisque eu dolor sagittis, tempus purus a, suscipit nisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut condimentum cursus blandit. Nullam consectetur, ipsum sed sodales elementum, lacus orci elementum augue, a sollicitudin diam tellus in libero. Donec vehicula neque turpis, vel facilisis orci dignissim vitae. Vivamus tempor accumsan porta. Mauris molestie sagittis sapien at sollicitudin. Morbi vehicula in justo eu luctus. Integer eu eros nec sapien tempus maximus ut eu purus. Suspendisse ut felis ipsum. Aliquam ligula lectus, feugiat a porta a, finibus sit amet erat. Nullam pulvinar mattis accumsan. Fusce ac rutrum nisl. Maecenas volutpat gravida nisl, et maximus dolor varius eget. Nulla et vehicula ligula. Curabitur tempor risus eu tortor efficitur, ac faucibus dui porttitor. Aliquam erat volutpat. Quisque eu dolor sagittis, tempus purus a, suscipit nisi." + #LF$ + #LF$ + "This should be the last paragraph (when this introduction text is displayed) that you see at the bottom. If you needed to scroll to see this, that is the problem. If it 'auto-scrolled' to the VERY bottom (the 'end of line' marker) then it is fixed!" + #LF$+ "END OF LINE."
Procedure WriteUserTextConsole(TextToWrite$, UserInputB.b = #False)
Protected ActiveGadget = GetActiveGadget() ;What was the current gadget at the beginning of this routine
If UserInputB
TextToWrite$ = "> " + TextToWrite$
EndIf
TextToWrite$ = GetGadgetText(#UserTextConsole) + TextToWrite$ + #LF$
SetGadgetAttribute(#UserTextConsole, #PB_Editor_ReadOnly, #False)
SetActiveGadget(#UserTextConsole)
SetGadgetText(#UserTextConsole, TextToWrite$)
SetActiveGadget(#UserInputEditor)
SetActiveGadget(#UserTextConsole)
SetGadgetText(#UserTextConsole, TextToWrite$)
SetGadgetAttribute(#UserTextConsole, #PB_Editor_ReadOnly, #True)
If ActiveGadget > -1
SetActiveGadget(ActiveGadget)
Else
;just in-case something happens and there is was no active gadget at the start of this procedure
Debug "No active gadget. Setting to #UserInputEditor."
SetActiveGadget(#UserInputEditor) ;No Active Gadget. Setting focus To User Input: EditorGadget(#UserInputEditor)
EndIf
EndProcedure
Procedure UnexpectedErrorHandler(ErrorText$)
WriteUserTextConsole(#LF$ + " --- AN UNEXPECTED ERROR OCCURED ---" + #LF$ + #LF$ + ErrorText$ + #LF$ + #LF$ + " --- END ERROR REPORT ---" + #LF$)
Debug ErrorText$
EndProcedure
Procedure.s InvalidInputErrorMsgS(ResetErrorMessageB.b = #False)
Static ErrorMsg$
If ResetErrorMessageB
ErrorMsg$ = ""
ProcedureReturn ""
EndIf
Select ErrorMsg$
Case "" : ErrorMsg$ = #DefaultInvalidUserInputErrorMsg
Case #DefaultInvalidUserInputErrorMsg : ErrorMsg$ = "Sorry. No valid command was entered."
Case "Sorry. No valid command was entered." : ErrorMsg$ = "Oops! I don't understand."
Case "Oops! I don't understand." : ErrorMsg$ = "That's...that's...just...meaningless."
Case "That's...that's...just...meaningless." : ErrorMsg$ = "Oh, come on!"
Case "Oh, come on!" : ErrorMsg$ = "No."
Case "No." : ErrorMsg$ = "Nope. Really."
Case "Nope. Really." : ErrorMsg$ = "Stop it!"
Case "Stop it!" : ErrorMsg$ = "That's it. I'm done with you."
Case "That's it. I'm done with you." : ErrorMsg$ = "."
Case "." : ErrorMsg$ = ".."
Case ".." : ErrorMsg$ = "..."
Case "..." : ErrorMsg$ = "Geez. Ok, whatever."
Default : ErrorMsg$ = #DefaultInvalidUserInputErrorMsg
EndSelect
ProcedureReturn ErrorMsg$
EndProcedure
Procedure UserInputHistoryProcessing(ProcessFlags, UserInputText$)
Static Dim UserInputHistoryArray$(#UserInputHistoryArraySize)
Static UserInputHistoryArrayWorkingElement = -1
Select ProcessFlags
Case #UserInputHistory_Append
For UserInputHistoryArrayWorkingElement = #UserInputHistoryArraySize To 1 Step -1
If UserInputHistoryArray$(UserInputHistoryArrayWorkingElement - 1) > ""
Swap UserInputHistoryArray$(UserInputHistoryArrayWorkingElement), UserInputHistoryArray$(UserInputHistoryArrayWorkingElement - 1)
EndIf
Next
UserInputHistoryArray$(0) = UserInputText$
UserInputHistoryArrayWorkingElement = -1
Case #UserInputHistory_ShowPrevious
If UserInputHistoryArray$(0) > ""
UserInputHistoryArrayWorkingElement = UserInputHistoryArrayWorkingElement + 1
If UserInputHistoryArrayWorkingElement > #UserInputHistoryArraySize
UserInputHistoryArrayWorkingElement = #UserInputHistoryArraySize
EndIf
If UserInputHistoryArray$(UserInputHistoryArrayWorkingElement)
SetGadgetText(#UserInputEditor, UserInputHistoryArray$(UserInputHistoryArrayWorkingElement))
Else
UserInputHistoryArrayWorkingElement = UserInputHistoryArrayWorkingElement - 1
SetGadgetText(#UserInputEditor, UserInputHistoryArray$(UserInputHistoryArrayWorkingElement))
EndIf
Else
SetGadgetText(#UserInputEditor, UserInputText$)
EndIf
Case #UserInputHistory_ShowNext
If UserInputHistoryArray$(0) > ""
UserInputHistoryArrayWorkingElement = UserInputHistoryArrayWorkingElement - 1
If UserInputHistoryArrayWorkingElement > -1
SetGadgetText(#UserInputEditor, UserInputHistoryArray$(UserInputHistoryArrayWorkingElement))
Else
UserInputHistoryArrayWorkingElement = -1
SetGadgetText(#UserInputEditor, "")
EndIf
Else
SetGadgetText(#UserInputEditor, UserInputText$)
EndIf
Default
WriteUserTextConsole("Invalid ProcessFlags supplied in UserInputHistoryProcessing(ProcessFlags).")
Debug "Invalid ProcessFlags supplied in UserInputHistoryProcessing(ProcessFlags)."
EndSelect
EndProcedure
Procedure.b ProcessParsedUserInputB(Array UserInputParsedArray$(1), NumberOfElements)
Protected i
Protected ExtractedUserInput$
;The main logic has been removed. This code just needs to return a test value to troubleshoot an inline js issue. End of line.
If NumberOfElements = 1
If UserInputParsedArray$(0) = "intro"
WriteUserTextConsole(#IntroductionResponse$)
Else
WriteUserTextConsole("Command test successful! (Any valid single-word entered will return successful. Any longer phrases will result in an invalid command response.) Typing 'intro' and pressing [enter] will polulate the screen with additional 'lorem ipsum' text. (It will re-display additional introduction text in the editor.)")
EndIf
ProcedureReturn #True
Else
ProcedureReturn #False
EndIf
EndProcedure
Procedure ProcessUserInput()
Protected UserInputText$
Protected Dim UserInputParsedArray$(0)
Protected NumberOfElements
UserInputText$ = Trim(GetGadgetText(#UserInputEditor))
If UserInputText$
WriteUserTextConsole(UserInputText$, #True)
UserInputHistoryProcessing(#UserInputHistory_Append, UserInputText$)
If IsRegularExpression(#UserInputRegExID)
NumberOfElements = ExtractRegularExpression(#UserInputRegExID, LCase(UserInputText$), UserInputParsedArray$())
If ProcessParsedUserInputB(UserInputParsedArray$(), NumberOfElements)
InvalidInputErrorMsgS(#True) ;Reset the error feedback sequence
Else
WriteUserTextConsole(InvalidInputErrorMsgS())
EndIf
Else
UnexpectedErrorHandler(RegularExpressionError())
EndIf
EndIf
SetGadgetText(#UserInputEditor, "")
FreeArray(UserInputParsedArray$())
EndProcedure
Procedure Event_UserInputChanges(ForceEnterKeyB.b = #False)
If (EventType() = #PB_EventType_Change And EventGadget() = 1) Or ForceEnterKeyB
If CountString(GetGadgetText(#UserInputEditor), #LF$)
SetGadgetText(#UserInputEditor, RemoveString(GetGadgetText(#UserInputEditor), #LF$))
ProcessUserInput()
ElseIf CountString(GetGadgetText(#UserInputEditor), "<")
UserInputHistoryProcessing(#UserInputHistory_ShowPrevious, Trim(RemoveString(GetGadgetText(#UserInputEditor), "<")))
ElseIf CountString(GetGadgetText(#UserInputEditor), ">")
UserInputHistoryProcessing(#UserInputHistory_ShowNext, Trim(RemoveString(GetGadgetText(#UserInputEditor), ">")))
ElseIf Len(GetGadgetText(#UserInputEditor)) > #UserInputEditorMaxLength
SetGadgetText(#UserInputEditor, Left(GetGadgetText(#UserInputEditor), #UserInputEditorMaxLength))
EndIf
EndIf
EndProcedure
Procedure Event_EnterButtonClicked()
If EventType() = #PB_EventType_LeftClick
SetGadgetText(#UserInputEditor, GetGadgetText(#UserInputEditor) + #LF$)
SetActiveGadget(#UserInputEditor)
Event_UserInputChanges(#True)
EndIf
EndProcedure
Procedure ResizeAndCenterGadgets()
Protected MaxWidth = 900
Protected MaxHeight = 9999
Protected NewWidth = WindowWidth(#MainBackgroundWindow) - 12
Protected NewHeight = WindowHeight(#MainBackgroundWindow) - 72
Protected NewLeft = 6
Protected NewTop = 6
If NewWidth > MaxWidth
NewWidth = MaxWidth
NewLeft = (WindowWidth(#MainBackgroundWindow) - MaxWidth) / 2
EndIf
If NewHeight > MaxHeight
NewHeight = MaxHeight
EndIf
ResizeGadget(#UserTextConsole, NewLeft, NewTop, NewWidth, NewHeight)
LoadFont(0, "", 18) : LoadFont(1, "", 14)
If NewWidth > 600
SetGadgetFont(#UserTextConsole, FontID(0))
SetGadgetFont(#UserInputEditor, FontID(0))
ResizeGadget(#UserInputEditor, NewLeft, NewHeight + 8, NewWidth, 35)
ResizeGadget(#UserEnterButton, NewLeft + NewWidth - 60, NewHeight + 46, 60, 22)
Else
SetGadgetFont(#UserTextConsole, FontID(1))
SetGadgetFont(#UserInputEditor, FontID(1))
ResizeGadget(#UserInputEditor, NewLeft, NewHeight + 8, NewWidth, 27)
ResizeGadget(#UserEnterButton, NewLeft + NewWidth - 60, NewHeight + 38, 60, 22)
EndIf
FreeFont(0) : FreeFont(1)
EndProcedure
Procedure Event_WindowResized()
ResizeAndCenterGadgets()
EndProcedure
Procedure Hello()
If OpenWindow(#MainBackgroundWindow, #PB_Ignore, #PB_Ignore, #PB_Ignore, #PB_Ignore, "Dark", #PB_Window_Background)
EditorGadget(#UserTextConsole, 8, 8, 306, 133, #PB_Editor_ReadOnly + #PB_Editor_WordWrap)
SetGadgetColor(#UserTextConsole, #PB_Gadget_BackColor, #UserTextConsoleBGColor)
SetGadgetColor(#UserTextConsole, #PB_Gadget_FrontColor, #UserTextConsoleTextColor)
SetGadgetColor(#UserTextConsole, #PB_Gadget_LineColor, #UserTextConsoleBGColor)
SetGadgetText(#UserTextConsole, #IntroductionResponse$ + #LF$)
EditorGadget(#UserInputEditor, 8, 150, 306, 27)
SetGadgetColor(#UserInputEditor, #PB_Gadget_BackColor, #UserInputEditorBGColor)
SetGadgetColor(#UserInputEditor, #PB_Gadget_FrontColor, #UserInputEditorTextColor)
SetGadgetColor(#UserInputEditor, #PB_Gadget_LineColor, #UserInputEditorTextColor)
ButtonGadget(#UserEnterButton, 254, 181, 60, 22, "Enter", #PB_Button_Default)
BindGadgetEvent(#UserInputEditor, @Event_UserInputChanges(), #PB_All)
BindGadgetEvent(#UserEnterButton, @Event_EnterButtonClicked(), #PB_All)
BindEvent(#PB_Event_SizeWindow, @Event_WindowResized(), 0, #UserTextConsole)
ResizeAndCenterGadgets()
SetActiveGadget(#UserInputEditor)
Else
Debug "Critical Error: Main application window failed to initialize!"
End
EndIf
EndProcedure
Procedure Main()
CreateRegularExpression(#UserInputRegExID, gUserInputRegEx$)
Hello()
EndProcedure
Main ()