Jump to content

Simple "chat" program with clickable links


therks
 Share

Recommended Posts

Thanks, @therks. Eventually, I made it that way as you suggested.

I made a user.ini text file wherein all users that will run the program it will automatically log to that "user.ini" using FileWrite() function and when they close the program, it will automatically delete the string match of the username that closes the program and be deleted in user.ini file. In that way, I can use _FileReadToArray to add these users in your GUI,:> and currently working on it.

Thanks again for the idea.:lol:

I'll share the outcome after.^_^

 

KS15

Programming is "To make it so simple that there are obviously no deficiencies" or "To make it so complicated that there are no obvious deficiencies" by C.A.R. Hoare.

Link to comment
Share on other sites

@therks,

:sweating: My added code is not good as it was I think...:lol: But can you try if that's Okay? Just add some dummy usernames in the User.ini file to see if it work. If you like, you can also modify my added codes just to make it more presentable^_^ and for my convenience....:>

#include <GUIConstants.au3>
#include <GUIEdit.au3>
#include <IE.au3>
#include <GuiRichEdit.au3>
#include <ColorConstants.au3>
#include <GUIConstants.au3>
#include <GUIEdit.au3>
#include <IE.au3>
#include <GuiRichEdit.au3>
#Include <Array.au3>
#Include <File.au3>
#include <FileConstants.au3>
#include <MsgBoxConstants.au3>
#include <WinAPIFiles.au3>

Opt('TrayIconDebug', 1)

If $CmdLine[0] And StringInStr(FileGetAttrib($CmdLine[1]), 'D') Then
    FileChangeDir($CmdLine[1])
EndIf

Global $CHAT_FILE = @ScriptDir & '\NetworkChat.txt'
ConsoleWrite($CHAT_FILE & @CRLF)

Global $UserPath = @ScriptDir & '\User.ini'

Local $hFileOpen = FileOpen($UserPath, $FO_APPEND)
If $hFileOpen = -1 Then
   MsgBox($MB_SYSTEMMODAL, "", "An error occurred whilst writing the temporary file.")
   Return False
EndIf
FileWrite($UserPath, @UserName)
FileClose($hFileOpen)

Local $xFileOpen = FileOpen($UserPath, $FO_READ)
If $xFileOpen = -1 Then
   MsgBox($MB_SYSTEMMODAL, "", "An error occurred when reading the file.")
   Return False
EndIf
Local $sFileRead = FileRead($xFileOpen)
FileClose($xFileOpen)

Main()

Func Main()
    Local $hGUIMain = GUICreate('Network Chat', 570, 440, Default, Default, $WS_OVERLAPPEDWINDOW)

    Local $oEmbedIE = _IECreateEmbedded()
    Local $ob_EmbedIE = GUICtrlCreateObj($oEmbedIE, 5, 5, 490, 300)
        GUICtrlSetResizing(-1, $GUI_DOCKBORDERS)

    _IENavigate($oEmbedIE, 'about:blank')

    Local $dm_AccelTab = GUICtrlCreateDummy()
    Local $dm_AccelCtrlA = GUICtrlCreateDummy()
    Local $dm_AccelEnter = GUICtrlCreateDummy()
    Local $dm_AccelShiftEnter = GUICtrlCreateDummy()
    Local $dm_AccelPgUp = GUICtrlCreateDummy()
    Local $dm_AccelPgDn = GUICtrlCreateDummy()
    Local $ed_Chat = GUICtrlCreateEdit('', 5, 310, 470, 60, BitOR($ES_WANTRETURN, $WS_VSCROLL, $ES_AUTOVSCROLL))
        GUICtrlSetResizing(-1, BitOR($GUI_DOCKSTATEBAR, $GUI_DOCKLEFT, $GUI_DOCKRIGHT))
        Local $aTabStop = [ 4 * 4 ]
        _GUICtrlEdit_SetTabStops($ed_Chat, $aTabStop)
    Local $bt_Send = GUICtrlCreateButton('>', 475, 310, 20, 60)
        GUICtrlSetResizing(-1, BitOR($GUI_DOCKSTATEBAR, $GUI_DOCKSIZE, $GUI_DOCKRIGHT))
        GUICtrlSetState(-1, $GUI_DEFBUTTON)

    Local $ch_Timestamps = GUICtrlCreateCheckbox('Show &timestamps', 5, 375, 200, 20)
        GUICtrlSetResizing(-1, BitOR($GUI_DOCKSTATEBAR, $GUI_DOCKSIZE, $GUI_DOCKLEFT))
    Local $ch_PromptURL = GUICtrlCreateCheckbox('&Confirm before opening links', 5, 395, 200, 20)
        GUICtrlSetResizing(-1, BitOR($GUI_DOCKSTATEBAR, $GUI_DOCKSIZE, $GUI_DOCKLEFT))
    Local $ra_Enter = GUICtrlCreateRadio('&1. Enter to send / Shift+Enter for new line', 280, 375, 215, 20)
        GUICtrlSetResizing(-1, BitOR($GUI_DOCKSTATEBAR, $GUI_DOCKSIZE, $GUI_DOCKRIGHT))
        GUICtrlSetState(-1, $GUI_CHECKED)
    Local $ra_ShiftEnter = GUICtrlCreateRadio('&2. Shift+Enter to send / Enter for new line', 280, 395, 215, 20)
        GUICtrlSetResizing(-1, BitOR($GUI_DOCKSTATEBAR, $GUI_DOCKSIZE, $GUI_DOCKRIGHT))
    Local $lb_Status = GUICtrlCreateLabel(' Chat file: ' & $CHAT_FILE, 0, 420, 500, 20, BitOR($SS_SUNKEN, $SS_CENTERIMAGE))
        GUICtrlSetResizing(-1, BitOR($GUI_DOCKSTATEBAR, $GUI_DOCKLEFT, $GUI_DOCKRIGHT))
        GUICtrlSetCursor(-1, 0)
    Local $UsrIn = GUICtrlCreateLabel($sFileRead, 500, 20)
                  GUICtrlSetColor($UsrIn, $COLOR_GREEN)
    Local $UsrGrp = GUICtrlCreateGroup("Active User:", 495, 5,72,300)
    Local $aAccel = [ _
        [ '{enter}', $dm_AccelEnter ], _
        [ '+{enter}', $dm_AccelShiftEnter ], _
        [ '{tab}', $dm_AccelTab ], _
        [ '{pgup}', $dm_AccelPgUp ], _
        [ '{pgdn}', $dm_AccelPgDn ], _
        [ '^a', $dm_AccelCtrlA ] ]

    GUISetAccelerators($aAccel)
    GUISetState()
    GUICtrlSetState($ed_Chat, $GUI_FOCUS)


    Local $sHTML, $aChatTime[2], $hFocused, $hIEControl = ControlGetHandle($hGUIMain, '', '[CLASS:Internet Explorer_Server; INSTANCE:1]')
    While 1
        $hFocused = _WinAPI_GetFocus()

        $aChatTime[0] = FileGetTime($CHAT_FILE, 0, 1)
        If $aChatTime[0] <> $aChatTime[1] Then
            $sHTML = _LoadChat(BitAND(GUICtrlRead($ch_Timestamps), $GUI_CHECKED))
            _IEDocWriteHTML($oEmbedIE, $sHTML)
            _IEAction($oEmbedIE, 'refresh')
            $oEmbedIE.document.parentwindow.scrollTo(0, $oEmbedIE.document.body.scrollHeight)
            $aChatTime[1] = $aChatTime[0]
        EndIf

        If $oEmbedIE.document.location.href <> 'about:blank' Then
            _IENavigate($oEmbedIE, 'about:blank')
            $aChatTime[1] = 0
        EndIf

        Local $oAutoItMonitor = $oEmbedIE.document.getElementById('autoit_monitor')
        If IsObj($oAutoItMonitor) And $oAutoItMonitor.value Then
            Local $sVal = $oAutoItMonitor.value
            If StringLeft($sVal, 4) = 'http' Then
                Local $sVal = StringReplace($sVal, '&amp;', '&') ; For some reason the JavaScript copying the URL always encodes ampersands to html entities
                If Not BitAND(GUICtrlRead($ch_PromptURL), $GUI_CHECKED) Or (MsgBox(0x124, 'URL', 'Open URL?' & @LF & $sVal, 0, $hGUIMain) = 6) Then
                    ShellExecute($sVal)
                EndIf
            ElseIf $sVal = 27 Then ; Escape
                ExitLoop
            ElseIf Not ($sVal = 17 Or $sVal >= 35 And $sVal <= 40) Then ; Ctrl, Home, End, Arrow keys
                ConsoleWrite($sVal & @CRLF)
                GUICtrlSetState($ed_Chat, $GUI_FOCUS)
            EndIf
            $oAutoItMonitor.value = ''
        EndIf

        Local $iMsg = GUIGetMsg()
        Switch $iMsg
            Case $lb_Status
                ShellExecute($CHAT_FILE)
            Case $ch_Timestamps
                $aChatTime[1] = 0
            Case $dm_AccelPgUp
                $oEmbedIE.document.parentwindow.scrollBy(0, -200)
            Case $dm_AccelPgDn
                $oEmbedIE.document.parentwindow.scrollBy(0, 200)
            Case $dm_AccelCtrlA
                If $hFocused = GUICtrlGetHandle($ed_Chat) Then _GUICtrlEdit_SetSel($ed_Chat, 0, -1)
            Case $dm_AccelEnter
                If $hFocused = GUICtrlGetHandle($ed_Chat) Then
                    If BitAND(GUICtrlRead($ra_Enter), $GUI_CHECKED) Then
                        _SendChat($ed_Chat)
                    Else
                        _GUICtrlEdit_ReplaceSel($ed_Chat, @CRLF)
                    EndIf
                EndIf
            Case $dm_AccelShiftEnter
                If $hFocused = GUICtrlGetHandle($ed_Chat) Then
                    If BitAND(GUICtrlRead($ra_ShiftEnter), $GUI_CHECKED) Then
                        _SendChat($ed_Chat)
                    Else
                        _GUICtrlEdit_ReplaceSel($ed_Chat, @CRLF)
                    EndIf
                EndIf
            Case $bt_Send
                _SendChat($ed_Chat)
            Case $dm_AccelTab
                If $hFocused = GUICtrlGetHandle($ed_Chat) Then
                    _GUICtrlEdit_ReplaceSel($ed_Chat, @TAB)
                Else
                    GUICtrlSetState($ed_Chat, $GUI_FOCUS)
                EndIf
            Case $GUI_EVENT_CLOSE
               Global $_Array
               _FileReadToArray ( @ScriptDir & '\User.ini', $_Array )
               $_Array = _DeleteArrayElementWithStringInstr ( $_Array, @UserName )
               _FileWriteFromArray (@ScriptDir & '\User.ini', $_Array, 1 )
                ExitLoop
        EndSwitch
    WEnd
EndFunc

Func _DeleteArrayElementWithStringInstr ( $_Array, $_String )
    Local $_Item
    For $_Element In $_Array
        If StringInStr ( $_Element, $_String ) <> 0 Then
            _ArrayDelete ( $_Array, $_Item )
        Else
            $_Item+=1
        EndIf
    Next
    Return ( $_Array )
EndFunc

Func _EncodeForFile($sString)
    $sString = StringStripCR($sString)
    $sString = StringReplace($sString, '\', '\\')
    $sString = StringReplace($sString, @LF, '\n')
    $sString = StringReplace($sString, @TAB, '\t')
    Return $sString
EndFunc

Func _EncodeFromFile($sString)
    $sString = StringReplace($sString, '<', '&lt;')
    $sString = StringReplace($sString, '>', '&gt;')
    $sString = StringFormat($sString)
    $sString = StringReplace($sString, @TAB, '&nbsp;&nbsp;&nbsp;&nbsp;')
    $sString = StringReplace($sString, @LF, '<br />')
    $sString = StringRegExpReplace($sString, '(https?://\S+)', '<span class="fakelink" onclick="document.getElementById(''autoit_monitor'').value=this.innerHTML">\1</span>') ;
    Return $sString
EndFunc

Func _SendChat($iCtrl)
    Local $sChat = StringStripWS(GUICtrlRead($iCtrl), 3)
    If $sChat Then
        FileWrite($CHAT_FILE, @CRLF & @YEAR & @MON & @MDAY & @HOUR & @MIN & @SEC & @TAB & @ComputerName & @TAB & _EncodeForFile($sChat))
        GUICtrlSetData($iCtrl, '')
        Return True
    EndIf
EndFunc

Func _LoadChat($iShowTS)
    Local $aLines = FileReadToArray($CHAT_FILE), _
    $sOutput  = '<style>' & @CRLF
    $sOutput &= 'body, table { margin: 0; font-family: Arial; font-size: 0.8em; border-collapse: collapse; width: 100%; } ' & @CRLF
    $sOutput &= 'tr { vertical-align: top; text-align: left; } ' & @CRLF
    $sOutput &= '.name_column { white-space: nowrap; } ' & @CRLF
    $sOutput &= '.text_column { width: 100%; } ' & @CRLF
    $sOutput &= '.row1 { background: #eee; } ' & @CRLF
    $sOutput &= '.date { background: #bef; text-align: center; border: solid #000; border-width: 1px 0; } ' & @CRLF
    $sOutput &= '.fakelink { text-decoration: underline; cursor: pointer; color: #08f; } ' & @CRLF
    If Not $iShowTS Then $sOutput &= '.timestamp { display: none }' & @CRLF
    $sOutput &= '</style>' & @CRLF
    $sOutput &= '<body onkeydown="document.getElementById(''autoit_monitor'').value=event.keyCode">' & @CRLF
    $sOutput &= '<table>' & @CRLF

    Local $sDateMem
    For $L = 0 To @extended-1
        If Not $aLines[$L] Then ContinueLoop

        Local $aRegExLine = StringRegExp($aLines[$L], '(.+)\t(.+)\t(.+)', 1), $sChat
        If Not @error Then
            $aDateTime = _FormatTime($aRegExLine[0])
            If $aDateTime[0] <> $sDateMem Then
                $sOutput &= '<tr><th class="date" colspan="2">' & $aDateTime[0] & '</th></tr>'
                $sDateMem = $aDateTime[0]
            EndIf

            $sOutput &= '<tr class="row' & Mod($L, 2) & '">' & _
                '<th class="name_column"><span class="timestamp">[' & $aDateTime[1] & '] </span>&lt;' & $aRegExLine[1] & '&gt;</th>' & _
                '<td class="text_column">' & _EncodeFromFile($aRegExLine[2]) & '</td></tr>' & @CRLF
        EndIf
    Next
    $sOutput &= '</table>'
    $sOutput &= '<input type="hidden" id="autoit_monitor" />'
    Return $sOutput
EndFunc

Func _FormatTime($sTime)
    Local $aMonths = StringSplit('Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec', '|')
    Local $aReturn[2]
    Local $aRegEx = StringRegExp($sTime, '(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})', 1)
    If Not @error Then
        $aReturn[0] = $aRegEx[0] &'-'& $aMonths[Int($aRegEx[1])] &'-'& $aRegEx[2]
        $aReturn[1] = $aRegEx[3] &':'& $aRegEx[4] &':'& $aRegEx[5]
    EndIf
    Return $aReturn
EndFunc

 

KS15

Programming is "To make it so simple that there are obviously no deficiencies" or "To make it so complicated that there are no obvious deficiencies" by C.A.R. Hoare.

Link to comment
Share on other sites

That looks like a good start.

A few things I noticed:

  • You should add a line ending to the username when you add it to the file [ FileWrite($UserPath, @UserName & @CRLF) ], otherwise the next name added will be on the same line.
  • When you're exiting the script, the line: _FileWriteFromArray (@ScriptDir & '\User.ini', $_Array, 1 ) will not write an empty array to file when the last user has been removed, instead it will just fail and that last username will be left in the file. Perhaps do a check if the array is empty, and then manually overwrite the user.ini, or even just delete it.
  • I would maybe shrink the display area a bit, so your username list will fit better beside it. Also you need to set the sizing properties for that list.
  • You also need to keep re-reading the username file and putting it in that Label control otherwise when a new user logs on, none of the existing users will see them.

 

Edited by therks
Link to comment
Share on other sites

@therks,

On 5/5/2018 at 10:54 PM, therks said:

You should add a line ending to the username when you add it to the file [ FileWrite($UserPath, @UserName & @CRLF) ], otherwise the next name added will be on the same line.

Yup noticed that one too and I already made it corrected accordingly. ^_^

 

On 5/5/2018 at 10:54 PM, therks said:

When you're exiting the script, the line: _FileWriteFromArray (@ScriptDir & '\User.ini', $_Array, 1 ) will not write an empty array to file when the last user has been removed, instead it will just fail and that last username will be left in the file. Perhaps do a check if the array is empty, and then manually overwrite the user.ini, or even just delete it.

definitely true, when it reaches to the last user, that code won't removed the last user but instead, it will fail. Yup, made it there as well thanks for checking.:D

 

On 5/5/2018 at 10:54 PM, therks said:

I would maybe shrink the display area a bit, so your username list will fit better beside it. Also you need to set the sizing properties for that list.

Okay, I'll check on this and see if I can shrink it a bit.

 

On 5/5/2018 at 10:54 PM, therks said:

You also need to keep re-reading the username file and putting it in that Label control otherwise when a new user logs on, none of the existing users will see them.

Yup and this is where i was stacked for a while. I tried adding it in the loop but the close event was affected with it, so I tried having a separate loop While 1.... WEnd but still having issue with the enter section and the loop continuously looping, So what I did is I added the re-reading part when the enter key was hit by the user. I mean, every time the user hits enter, the FileRead() function will continue reading. Hahaha a silly idea but could not think for one way to solve this.:sweating:

 

Programming is "To make it so simple that there are obviously no deficiencies" or "To make it so complicated that there are no obvious deficiencies" by C.A.R. Hoare.

Link to comment
Share on other sites

I don't know if you're still interested in this @KickStarter15, but I kept modifying my code and I eventually decided to add a userlist as well.

Maybe you'll find something interesting.

#NoTrayIcon
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Icon=NetworkChat.ico
#AutoIt3Wrapper_UseX64=y
#AutoIt3Wrapper_Res_Fileversion=1.0.0.21
#AutoIt3Wrapper_Res_Fileversion_AutoIncrement=y
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****

#include <WinAPISys.au3>
#include <WinAPIsysinfoConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <StaticConstants.au3>
#include <ListBoxConstants.au3>
#include <TrayConstants.au3>
#include <GUIEdit.au3>
#include <GuiListView.au3>
#include <IE.au3>
#include <Date.au3>

If $CmdLine[0] And StringInStr(FileGetAttrib($CmdLine[1]), 'D') Then
    FileChangeDir($CmdLine[1])
EndIf

Global Const $SINGLETON_TITLE = String(StringToBinary('therks - Network Chat')), _
    $APP_NAME = 'Network Chat', _
    $USER_NAME = @ComputerName, _
    $CHAT_FILE = @WorkingDir & '\NetworkChat.txt', _
    $USER_FILE = @WorkingDir & '\NetworkChatUsers.ini', _
    $CSS_FILE = @AppDataDir & '\NetworkChat.css', _
    $INI_FILE = @AppDataDir & '\NetworkChat.ini', $INI_SECTION = 'CONFIG', $INI_HISTORY = 'History', _
    $INI_ENTERSTYLE = 'EnterStyle', $INI_ONTOP = 'OnTop', $INI_STARTMIN = 'StartMin', $INI_MINTOTRAY = 'MinToTray', $INI_CLOSEMIN = 'CloseMin', $INI_SHOWUSERS = 'ShowUsers', _
    $INI_ESCCLOSE = 'EscClose', $INI_SHOWTIMES = 'ShowTimes', $INI_CONFIRMLINK = 'ConfirmLink'

Global Enum $GLOBAL_WIN, $GLOBAL_EMBED, $GLOBAL_TOGGLE, $GLOBAL_UB
Global $GLOBAL_ARRAY[$GLOBAL_UB]

Global $HISTORY_LIST[11]

Main()

Func Main()
    If 'Singleton window' Then
        If WinExists($SINGLETON_TITLE) Then
            ControlSetText('[last]', '', 'Edit1', 'Show')
            Exit
        EndIf
        GUICreate($SINGLETON_TITLE)
        Local $ed_Singleton = GUICtrlCreateEdit('', 0, 0)
    EndIf

    Opt('MustDeclareVars', 1)
    Opt('TrayMenuMode', 3)
    TraySetToolTip($APP_NAME)
    TraySetState()

    _CSSFile()

    Local $iCfgEnterStyle = Int(IniRead($INI_FILE, $INI_SECTION, $INI_ENTERSTYLE, 0))
    Local $iCfgShowTimes = Int(IniRead($INI_FILE, $INI_SECTION, $INI_SHOWTIMES, 0))
    Local $iCfgConfirmLink = Int(IniRead($INI_FILE, $INI_SECTION, $INI_CONFIRMLINK, 0))
    Local $iCfgEscKeyClose = Int(IniRead($INI_FILE, $INI_SECTION, $INI_ESCCLOSE, 0))
    Local $iCfgStartMin = Int(IniRead($INI_FILE, $INI_SECTION, $INI_STARTMIN, 0))
    Local $iCfgMinToTray = Int(IniRead($INI_FILE, $INI_SECTION, $INI_MINTOTRAY, 0))
    Local $iCfgCloseMin = Int(IniRead($INI_FILE, $INI_SECTION, $INI_CLOSEMIN, 0))
    Local $iCfgOnTop = Int(IniRead($INI_FILE, $INI_SECTION, $INI_ONTOP, 0))
    Local $iCfgShowUsers = Int(IniRead($INI_FILE, $INI_SECTION, $INI_SHOWUSERS, 1))

    If 'Tray Menu Setup' Then ; =========================================================================================================
        TraySetClick(16)
        Local $ti_Open, $ti_Exit
        $ti_Open = TrayCreateItem('&Open')
            TrayItemSetState(-1, $TRAY_DEFAULT)
        $ti_Exit = TrayCreateItem('E&xit')
    EndIf ; =========================================================================================================

    Local $aTabStop = [ 4 * 4 ]
    If 'Main window' Then ; ============================================================================================================
        Local Enum $ACC_CTRL_TAB, $ACC_CTRL_A, $ACC_ENTER, $ACC_SHIFT_ENTER, $ACC_PGUP, $ACC_PGDN, $ACC_CTRL_UP, $ACC_CTRL_DN, $ACC_ESC, $ACC_UB
        Local $hGUIMain, $oEmbeddedIE, $ob_EmbedIE, $li_Users, $dm_Accel[$ACC_UB], $bt_Options, $ed_Chat, $bt_Send, $lb_Status

        $hGUIMain = GUICreate($APP_NAME, 500, 415, Default, Default, $WS_OVERLAPPEDWINDOW)

        $oEmbeddedIE = _IECreateEmbedded()
        $ob_EmbedIE = GUICtrlCreateObj($oEmbeddedIE, 0, 0, 400, 310)
        $li_Users = GUICtrlCreateList('', 405, 0, 95, 310, BitOR($LBS_NOINTEGRALHEIGHT, $LBS_SORT, $LBS_NOSEL))
            GUICtrlSetResizing(-1, BitOR(BitXOR($GUI_DOCKBORDERS, $GUI_DOCKLEFT), $GUI_DOCKWIDTH))
        If Not $iCfgShowUsers Then
            GUICtrlSetState(-1, $GUI_HIDE)
        EndIf

        _IENavigate($oEmbeddedIE, 'about:blank')

        $dm_Accel[$ACC_CTRL_TAB]    = GUICtrlCreateDummy()
        $dm_Accel[$ACC_CTRL_A]      = GUICtrlCreateDummy()
        $dm_Accel[$ACC_ENTER]       = GUICtrlCreateDummy()
        $dm_Accel[$ACC_SHIFT_ENTER] = GUICtrlCreateDummy()
        $dm_Accel[$ACC_PGUP]        = GUICtrlCreateDummy()
        $dm_Accel[$ACC_PGDN]        = GUICtrlCreateDummy()
        $dm_Accel[$ACC_CTRL_UP]     = GUICtrlCreateDummy()
        $dm_Accel[$ACC_CTRL_DN]     = GUICtrlCreateDummy()
        $dm_Accel[$ACC_ESC]         = GUICtrlCreateDummy()

        $bt_Options = GUICtrlCreateButton('+', 480, 315, 20, 20)
            GUICtrlSetResizing(-1, BitOR($GUI_DOCKSTATEBAR, $GUI_DOCKSIZE, $GUI_DOCKRIGHT))
            GUICtrlSetTip(-1, 'Options (Alt+O)')
        $ed_Chat = GUICtrlCreateEdit('', 0, 315, 480, 80, BitOR($ES_WANTRETURN, $WS_VSCROLL, $ES_AUTOVSCROLL))
            GUICtrlSetResizing(-1, BitOR($GUI_DOCKSTATEBAR, $GUI_DOCKLEFT, $GUI_DOCKRIGHT))
            _GUICtrlEdit_SetTabStops($ed_Chat, $aTabStop)
        $bt_Send = GUICtrlCreateButton('>', 480, 335, 20, 60)
            GUICtrlSetResizing(-1, BitOR($GUI_DOCKSTATEBAR, $GUI_DOCKSIZE, $GUI_DOCKRIGHT))
            GUICtrlSetState(-1, $GUI_DEFBUTTON)

        $lb_Status = GUICtrlCreateLabel(' Chat file: ' & $CHAT_FILE, 0, 395, 500, 20, BitOR($SS_SUNKEN, $SS_CENTERIMAGE))
            GUICtrlSetResizing(-1, BitOR($GUI_DOCKSTATEBAR, $GUI_DOCKLEFT, $GUI_DOCKRIGHT))
            GUICtrlSetCursor(-1, 0)
    EndIf ; =============================================================================================================================

    If 'Options Window' Then ; =========================================================================================================
        Local $hGUIOptions, $ra_EnterStyleNoShift, $ra_EnterStyleShift, $ch_OnTop, $ch_StartMin, $ch_MinToTray, $ch_CloseMin, $ch_EscKeyClose, $ch_Timestamps, $ch_ShowUsers, $ch_ConfirmLink, $ch_RawHTML, $bt_CSS, $bt_CSSReset

        $hGUIOptions = GUICreate('Options', 240, 275, Default, Default, BitOR($WS_CAPTION, $WS_SYSMENU), $WS_EX_TOOLWINDOW, $hGUIMain)

        GUICtrlCreateGroup('&Enter key behaviour:', 5, 5, 230, 60)
        $ra_EnterStyleNoShift = GUICtrlCreateRadio('Enter to send (Shift+Enter for new line)', 10, 20, 215, 20)
            GUICtrlSetState(-1, $GUI_CHECKED)
        $ra_EnterStyleShift = GUICtrlCreateRadio('Shift+Enter to send (Enter for new line)', 10, 40, 215, 20)
            If $iCfgEnterStyle Then GUICtrlSetState(-1, $GUI_CHECKED)

        $ch_OnTop = GUICtrlCreateCheckbox('Keep &window on top', 5, 70, 200, 20)
            If $iCfgOnTop Then GUICtrlSetState(-1, $GUI_CHECKED)
        $ch_StartMin = GUICtrlCreateCheckbox('&Start minimized/hidden', 5, 90, 215, 20)
            If $iCfgStartMin Then GUICtrlSetState(-1, $GUI_CHECKED)
        $ch_MinToTray = GUICtrlCreateCheckbox('&Minimize to tray (hide)', 5, 110, 200, 20)
            If $iCfgMinToTray Then GUICtrlSetState(-1, $GUI_CHECKED)
        $ch_CloseMin = GUICtrlCreateCheckbox('&Close minimizes', 5, 130, 215, 20)
            If $iCfgCloseMin Then GUICtrlSetState(-1, $GUI_CHECKED)
        $ch_EscKeyClose = GUICtrlCreateCheckbox('Escape &key closes', 5, 150, 215, 20)
            If $iCfgEscKeyClose Then GUICtrlSetState(-1, $GUI_CHECKED)
        $ch_ShowUsers = GUICtrlCreateCheckbox('Show &users', 5, 170, 200, 20)
            If $iCfgShowUsers Then GUICtrlSetState(-1, $GUI_CHECKED)
        $ch_Timestamps = GUICtrlCreateCheckbox('Show &timestamps', 5, 190, 200, 20)
            If $iCfgShowTimes Then GUICtrlSetState(-1, $GUI_CHECKED)
        $ch_ConfirmLink = GUICtrlCreateCheckbox('Confirm &before opening links', 5, 210, 200, 20)
            If $iCfgConfirmLink Then GUICtrlSetState(-1, $GUI_CHECKED)
        $ch_RawHTML = GUICtrlCreateCheckbox('&View Chat HTML', 5, 230, 200, 20)

        $bt_CSS = GUICtrlCreateButton('Edit CSS &File', 5, 250, 115, 20)
        $bt_CSSReset = GUICtrlCreateButton('&Reset CSS File', 120, 250, 115, 20)

    EndIf ; =============================================================================================================================

    Local $aAccel = [ _
        [ '{enter}',  $dm_Accel[$ACC_ENTER] ], _
        [ '+{enter}', $dm_Accel[$ACC_SHIFT_ENTER] ], _
        [ '^{tab}',   $dm_Accel[$ACC_CTRL_TAB] ], _
        [ '{pgup}',   $dm_Accel[$ACC_PGUP] ], _
        [ '{pgdn}',   $dm_Accel[$ACC_PGDN] ], _
        [ '^{up}',    $dm_Accel[$ACC_CTRL_UP] ], _
        [ '^{down}',    $dm_Accel[$ACC_CTRL_DN] ], _
        [ '{esc}',    $dm_Accel[$ACC_ESC] ], _
        [ '^a',       $dm_Accel[$ACC_CTRL_A] ], _
        [ '!o',       $bt_Options ] _
    ]
    GUISetAccelerators($aAccel, $hGUIMain)
    $GLOBAL_ARRAY[$GLOBAL_WIN] = $hGUIMain
    $GLOBAL_ARRAY[$GLOBAL_EMBED] = $ob_EmbedIE
    $GLOBAL_ARRAY[$GLOBAL_TOGGLE] = $iCfgShowUsers
    GUIRegisterMsg($WM_GETMINMAXINFO, WM_GETMINMAXINFO)
    GUIRegisterMsg($WM_PAINT, WM_PAINT)

    If $iCfgStartMin Then
        If Not $iCfgMinToTray Then
            GUISetState(@SW_SHOWMINIMIZED, $hGUIMain)
        EndIf
    Else
        GUISetState(@SW_SHOW, $hGUIMain)
    EndIf
    GUICtrlSetState($ed_Chat, $GUI_FOCUS)

    If $iCfgOnTop Then WinSetOnTop($hGUIMain, '', 1)

    _IEErrorNotify(False)
    Local $bReload = True, $sHTML, $aChatFileTime[2], $oDoc = _IEDocGetObj($oEmbeddedIE), $oAutoItMonitor, $sMonitorValue, $iTM, $aGM, $iUserPingTimer, $sUserList, $iPing, $aUserData
    While 1
        If GUICtrlRead($ed_Singleton) Then
            GUICtrlSetData($ed_Singleton, '')
            GUISetState(@SW_SHOWNORMAL, $hGUIMain)
            WinActivate($hGUIMain)
        EndIf

        If TimerDiff($iUserPingTimer) > 2000 Then
            $iUserPingTimer = TimerInit()
            IniWrite($USER_FILE, 'Users', $USER_NAME, _NowCalc())

            $sUserList = ''
            $aUserData = IniReadSection($USER_FILE, 'Users')
            For $i = 1 To $aUserData[0][0]
                $iPing = _DateDiff('s', $aUserData[$i][1], _NowCalc())
                If $iPing > 30 Then
                    IniDelete($USER_FILE, 'Users', $aUserData[$i][0])
                EndIf
                If $aUserData[$i][0] = $USER_NAME Then $aUserData[$i][0] = '@' & $aUserData[$i][0]

                $sUserList &= '|' & $aUserData[$i][0]
                Assign('USERPING_' & StringToBinary($aUserData[$i][0]), $iPing, 2)
            Next
            GUICtrlSetData($li_Users, $sUserList)
        EndIf

        ; Check modified time on chat file, refresh if changes detected
        $aChatFileTime[0] = FileGetTime($CHAT_FILE, 0, 1)
        If $bReload Or $aChatFileTime[0] <> $aChatFileTime[1] Then
            $sHTML = _LoadChat(_IsChecked($ch_Timestamps))
            If _IsChecked($ch_RawHTML) Then
                $sHTML = StringReplace($sHTML, '<', '<')
                $sHTML = StringReplace($sHTML, '>', '>')
                $sHTML = '<pre>' & $sHTML & '</pre>'
            EndIf

            _IEDocWriteHTML($oEmbeddedIE, $sHTML)
            _IEAction($oEmbeddedIE, 'refresh')
            $oDoc = _IEDocGetObj($oEmbeddedIE)
            $oDoc.parentwindow.scrollTo(0, $oDoc.body.scrollHeight) ; Scroll to bottom
            $aChatFileTime[1] = $aChatFileTime[0]
            Local $aFormatTime = _FormatTime($aChatFileTime[0])
            GUICtrlSetData($lb_Status, ' Chat file: ' & $CHAT_FILE & ' | Last update: ' & $aFormatTime[1])
            If Not $bReload And Not WinActive($hGUIMain) Then
                TrayTip($APP_NAME, '[' & $aFormatTime[1] & '] New message', 5)
            EndIf
            $bReload = False
        EndIf

        ; If the embedded browser somehow navigates away
        If IsObj($oDoc) Then
            If $oDoc.location.href <> 'about:blank' Then
                _IENavigate($oEmbeddedIE, 'about:blank')
                $bReload = True
            EndIf

            $oAutoItMonitor = _IEGetObjById($oEmbeddedIE, 'autoit_monitor')
            If IsObj($oAutoItMonitor) And $oAutoItMonitor.value Then
                $sMonitorValue = $oAutoItMonitor.value
                If StringLeft($sMonitorValue, 4) = 'URL:' Then
                    $sMonitorValue = StringReplace(StringTrimLeft($sMonitorValue, 4), '&', '&') ; For some reason the JavaScript copying the URL always encodes ampersands to html entities
                    If Not _IsChecked($ch_ConfirmLink) Or (MsgBox(0x124, 'URL', 'Open URL?' & @LF & $sMonitorValue, 0, $hGUIMain) = 6) Then
                        ShellExecute($sMonitorValue)
                    EndIf
                ElseIf StringLeft($sMonitorValue, 4) = 'KEY:' Then
                    Switch StringTrimLeft($sMonitorValue, 4)
                        Case 27 ; Escape
                            ExitLoop
                        Case 17, 35 To 40
                            ; Do nothing - allows Ctrl, Home/End, & arrow keys
                        Case Else ; Any other key: focus edit control
                            GUICtrlSetState($ed_Chat, $GUI_FOCUS)
                    EndSwitch
                EndIf
                $oAutoItMonitor.value = '' ; Always clear monitor
            EndIf
        EndIf

        $iTM = TrayGetMsg()
        Switch $iTM
            Case $ti_Open
                GUISetState(@SW_SHOWNORMAL, $hGUIMain)
                WinActivate($hGUIMain)
            Case $ti_Exit
                _Exit()
        EndSwitch

        $aGM = GUIGetMsg(1)
        Switch $aGM[0]
            Case $li_Users
                If GUICtrlRead($li_Users) Then
                    ToolTip(GUICtrlRead($li_Users) & ' - Ping: ' & Eval('USERPING_' & StringToBinary(GUICtrlRead($li_Users))) & 's')
                EndIf
            Case $ra_EnterStyleNoShift
                $iCfgEnterStyle = 0
                IniWrite($INI_FILE, $INI_SECTION, $INI_ENTERSTYLE, $iCfgEnterStyle)
            Case $ra_EnterStyleShift
                $iCfgEnterStyle = 1
                IniWrite($INI_FILE, $INI_SECTION, $INI_ENTERSTYLE, $iCfgEnterStyle)
            Case $ch_OnTop
                $iCfgOnTop = _SetSetting($aGM[0], $INI_ONTOP)
                WinSetOnTop($hGUIMain, '', $iCfgOnTop)
            Case $ch_StartMin
                $iCfgStartMin = _SetSetting($aGM[0], $INI_STARTMIN)
            Case $ch_MinToTray
                $iCfgMinToTray = _SetSetting($aGM[0], $INI_MINTOTRAY)
            Case $ch_CloseMin
                $iCfgCloseMin = _SetSetting($aGM[0], $INI_CLOSEMIN)
            Case $ch_EscKeyClose
                $iCfgEscKeyClose = _SetSetting($aGM[0], $INI_ESCCLOSE)
            Case $ch_ShowUsers
                $iCfgShowUsers = _SetSetting($aGM[0], $INI_SHOWUSERS)
                $GLOBAL_ARRAY[$GLOBAL_TOGGLE] = $iCfgShowUsers
                If $iCfgShowUsers Then
                    GUICtrlSetState($li_Users, $GUI_SHOW)
                Else
                    GUICtrlSetState($li_Users, $GUI_HIDE)
                EndIf
            Case $ch_Timestamps
                $bReload = True ; Causes chat refresh
                $iCfgShowTimes = _SetSetting($aGM[0], $INI_SHOWTIMES)
            Case $ch_ConfirmLink
                $iCfgConfirmLink = _SetSetting($aGM[0], $INI_CONFIRMLINK)

            Case $ch_RawHTML
                $bReload = True ; Causes chat refresh
            Case $bt_CSS
                ShellExecute($CSS_FILE)
            Case $bt_CSSReset
                If _CSSFile(1) Then
                    MsgBox(0x40, 'CSS File', 'CSS file restored', 0, $hGUIOptions)
                Else
                    MsgBox(0x30, 'CSS File', 'Unable to restore CSS file', 0, $hGUIOptions)
                EndIf

            Case $dm_Accel[$ACC_PGUP]
                $oDoc.parentwindow.scrollBy(0, -200)
            Case $dm_Accel[$ACC_PGDN]
                $oDoc.parentwindow.scrollBy(0, 200)
            Case $dm_Accel[$ACC_CTRL_UP]
                GUICtrlSetData($ed_Chat, _SendHistory(1))
            Case $dm_Accel[$ACC_CTRL_DN]
                GUICtrlSetData($ed_Chat, _SendHistory(-1))
            Case $dm_Accel[$ACC_CTRL_A]
                If _IsFocused($ed_Chat) Then _GUICtrlEdit_SetSel($ed_Chat, 0, -1)
            Case $dm_Accel[$ACC_ENTER]
                If _IsFocused($ed_Chat) Then
                    If _IsChecked($ra_EnterStyleNoShift) Then
                        _SendChat($ed_Chat)
                        $bReload = True
                    Else
                        _GUICtrlEdit_ReplaceSel($ed_Chat, @CRLF)
                    EndIf
                EndIf
            Case $dm_Accel[$ACC_SHIFT_ENTER]
                If _IsFocused($ed_Chat) Then
                    If _IsChecked($ra_EnterStyleShift) Then
                        _SendChat($ed_Chat)
                        $bReload = True
                    Else
                        _GUICtrlEdit_ReplaceSel($ed_Chat, @CRLF)
                    EndIf
                EndIf
            Case $dm_Accel[$ACC_CTRL_TAB]
                If _IsFocused($ed_Chat) Then
                    _GUICtrlEdit_ReplaceSel($ed_Chat, @TAB)
                EndIf

            Case $bt_Send
                _SendChat($ed_Chat)
                $bReload = True
            Case $bt_Options
                Local $aMainPos = WinGetPos($hGUIMain)
                Local $aOptPos = WinGetPos($hGUIOptions)
                WinMove($hGUIOptions, '', _
                    $aMainPos[0]+($aMainPos[2]-$aOptPos[2])/2, _
                    $aMainPos[1]+($aMainPos[3]-$aOptPos[3])/2)
                GUISetState(@SW_SHOW, $hGUIOptions)
                WinActivate($hGUIOptions)
            Case $lb_Status
                ShellExecute($CHAT_FILE) ; Open raw chat file

            Case $dm_Accel[$ACC_ESC]
                If _IsChecked($ch_EscKeyClose) Then ContinueCase
            Case $GUI_EVENT_CLOSE
                If $aGM[1] = $hGUIMain Then
                    If _IsChecked($ch_CloseMin) Then
                        ContinueCase
                    Else
                        _Exit()
                    EndIf
                ElseIf $aGM[1] = $hGUIOptions Then
                    GUISetState(@SW_HIDE, $hGUIOptions)
                    WinActivate($hGUIMain)
                EndIf
            Case $GUI_EVENT_MINIMIZE
                GUISetState(@SW_MINIMIZE, $hGUIMain)
                If _IsChecked($ch_MinToTray) Then
                    GUISetState(@SW_HIDE, $hGUIMain)
                    TraySetState($TRAY_ICONSTATE_SHOW)
                EndIf
            Case $GUI_EVENT_MOUSEMOVE
                ToolTip('')
        EndSwitch
    WEnd
EndFunc

Func _Exit()
    IniDelete($USER_FILE, 'Users', $USER_NAME)
    Exit
EndFunc

Func _EncodeMessage($sString)
    $sString = StringStripCR($sString)
    $sString = StringReplace($sString, '%', '%%')
    $sString = StringReplace($sString, '\', '\\')
    $sString = StringReplace($sString, @LF, '\n')
    $sString = StringReplace($sString, @TAB, '\t')
    Return $sString
EndFunc

Func _DecodeMessage($sString)
    $sString = StringFormat($sString)
    $sString = StringReplace($sString, '<', '<')
    $sString = StringReplace($sString, '>', '>')
    $sString = StringReplace($sString, @TAB, '    ')
    $sString = StringReplace($sString, @LF, '<br />' & @CRLF & '        ') ; Tabs for HTML indentation
    $sString = StringRegExpReplace($sString, '((?:file|https?)://\S+|\\\\\S+\\\S*)', _
        '<span class="link" onclick="document.getElementById(''autoit_monitor'').value=''URL:''+this.innerHTML">\1</span>')
    Return $sString
EndFunc

Func _SendChat($iCtrl)
    Local $sMessage = StringStripWS(GUICtrlRead($iCtrl), 3)
    If $sMessage Then
        FileWrite($CHAT_FILE, @CRLF & @YEAR & @MON & @MDAY & @HOUR & @MIN & @SEC & @TAB & $USER_NAME & @TAB & _EncodeMessage($sMessage))
        _AddHistory($sMessage)
        GUICtrlSetData($iCtrl, '')
    EndIf
EndFunc

Func _LoadChat($iShowTimes)
    Local Enum $RE_DATETIME, $RE_USER, $RE_TEXT
    Local Enum $DT_DATE, $DT_TIME
    Local $sOutput, $sDateMem, $aLines, $iLineCount, $iLineTrack = 0, $aRegExLine, $aDateTime

    $sOutput = StringFormat('<html>\r\n<head>\r\n\t<link href="%s" rel="stylesheet">\r\n</head>\r\n', $CSS_FILE)
    $sOutput &= '<body onkeydown="document.getElementById(''autoit_monitor'').value=''KEY:''+event.keyCode">' & @CRLF
    $sOutput &= '<table>' & @CRLF

    $aLines = FileReadToArray($CHAT_FILE)
    $iLineCount = @extended
    For $L = 0 To $iLineCount-1
        If Not StringStripWS($aLines[$L], 3) Then ContinueLoop

        $aRegExLine = StringRegExp($aLines[$L], '(\d{14})\t(.+)\t(.+)', 1)
        If Not @error Then
            $aDateTime = _FormatTime($aRegExLine[$RE_DATETIME])
            If $aDateTime[$DT_DATE] <> $sDateMem Then
                $sOutput &= '<tr><td class="date" colspan="2">' & $aDateTime[$DT_DATE] & '</td></tr>' & @CRLF
                $sDateMem = $aDateTime[$DT_DATE]
                $iLineTrack = 0
            EndIf

            $sOutput &= '<tr class="rowOffset' & Mod($iLineTrack, 2) & ' user' & $aRegExLine[$RE_USER] & '">' & @CRLF
            $sOutput &= '   <td class="name_column">' & @CRLF
            If $iShowTimes Then $sOutput &= '       <span class="timestamp">[' & $aDateTime[$DT_TIME] & '] </span>' & @CRLF
            $sOutput &= '       <span class="username"><' & $aRegExLine[$RE_USER] & '></span> ' & @CRLF
            $sOutput &= '   </td>' & @CRLF
            $sOutput &= '   <td class="text_column">' & @CRLF
            $sOutput &= '       ' & _DecodeMessage($aRegExLine[$RE_TEXT]) & @CRLF
            $sOutput &= '   </td>' & @CRLF
            $sOutput &= '</tr>' & @CRLF
            $iLineTrack += 1
        EndIf
    Next
    $sOutput &= '</table>' & @CRLF
    $sOutput &= StringFormat('<input type="hidden" id="autoit_monitor" />\r\n</body>\r\n</html>')
    Return $sOutput
EndFunc

Func _FormatTime($sTime, $bToString = False)
    Local $aMonths = StringSplit('Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec', '|')
    Local $aRegEx = StringRegExp($sTime, '(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})', 1)
    Local $aReturn[2]
    If Not @error Then
        $aReturn[0] = $aRegEx[0] &'-'& $aMonths[Int($aRegEx[1])] &'-'& $aRegEx[2]
        $aReturn[1] = $aRegEx[3] &':'& $aRegEx[4] &':'& $aRegEx[5]
    EndIf

    If $bToString Then Return $aReturn[0] &' '& $aReturn[1]
    Return $aReturn
EndFunc

Func _AddHistory($sMessage)
    Local Const $LIST = '0123456789'
    _SendHistory(0)
    $sMessage = _EncodeMessage($sMessage)

    Local $sKey, $sKeyList = $HISTORY_LIST[10]
    For $i = 0 To StringLen($sKeyList)-1
        If $sMessage = $HISTORY_LIST[$i] Then
            $HISTORY_LIST[10] = $i & StringReplace($sKeyList, String($i), '')
            Return
        EndIf
    Next

    Local $sNext = StringLeft(StringRegExpReplace($LIST, '[' & $sKeyList & ']', ''), 1)
    If Not $sNext Then
        $sNext = StringRight($sKeyList, 1)
        $sKeyList = StringTrimRight($sKeyList, 1)
    EndIf

    $HISTORY_LIST[10] = $sNext & $sKeyList
    $HISTORY_LIST[Int($sNext)] = $sMessage
EndFunc

Func _SendHistory($iDir = 0)
    Static $iPosition = 0

    Local $sKeyList = $HISTORY_LIST[10]
    Local $sKeyLen = StringLen($sKeyList)
    Local $sKey

    If $iDir < 0 Then
        $iPosition = $iPosition > 0 ? $iPosition - 1 : 0
    ElseIf $iDir > 0 Then
        $iPosition = $iPosition < $sKeyLen ? $iPosition + 1 : $sKeyLen
    Else
        $iPosition = 0
    EndIf

    $sKey = StringMid($sKeyList, $iPosition, 1)
    Return $sKey ? $HISTORY_LIST[Int($sKey)] : ''
EndFunc

Func _SetSetting($idCtrl, $sIniKey)
    Local $iSetting = 0
    If _IsChecked($idCtrl) Then $iSetting = 1
    IniWrite($INI_FILE, $INI_SECTION, $sIniKey, $iSetting)

    Return $iSetting
EndFunc

Func _IsChecked($idCtrl)
    Return BitAND(GUICtrlRead($idCtrl), $GUI_CHECKED)
EndFunc

Func _IsFocused($idCtrl)
    Return _WinAPI_GetFocus() = GUICtrlGetHandle($idCtrl)
EndFunc

Func _CSSFile($iForce = 0)
    Return FileInstall('NetworkChat.css', $CSS_FILE, $iForce)
EndFunc

Func WM_GETMINMAXINFO($hWnd, $iMsg, $wParam, $lParam)
    Local $tMinMaxInfo = DllStructCreate('int;int;int;int;int;int;int;int;int;int', $lParam)
    If $hWnd = $GLOBAL_ARRAY[$GLOBAL_WIN] Then
        DllStructSetData($tMinMaxInfo, 7, 300); min width
        DllStructSetData($tMinMaxInfo, 8, 300); min height
        DllStructSetData($tMinMaxInfo, 9, @DesktopWidth); max width
        DllStructSetData($tMinMaxInfo, 10, @DesktopHeight); max height
        Return
    EndIf
EndFunc

Func WM_PAINT($hWnd, $iMsg, $wParam, $lParam)
    If $hWnd = $GLOBAL_ARRAY[$GLOBAL_WIN] Then
        Local $aClient = WinGetClientSize($hWnd)
        If $GLOBAL_ARRAY[$GLOBAL_TOGGLE] Then
            GUICtrlSetPos($GLOBAL_ARRAY[$GLOBAL_EMBED], 0, 0, $aClient[0] - 100, $aClient[1] - 105)
        Else
            GUICtrlSetPos($GLOBAL_ARRAY[$GLOBAL_EMBED], 0, 0, $aClient[0], $aClient[1] - 105)
        EndIf
    EndIf
EndFunc

 

Edited by therks
Link to comment
Share on other sites

@therks, off course I am^_^. I tried also changing you code to met my desired but as of this moment, I think this is great. Thanks, appreciated so much:)....

Programming is "To make it so simple that there are obviously no deficiencies" or "To make it so complicated that there are no obvious deficiencies" by C.A.R. Hoare.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...