Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F633495
irc_window.as
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Authored By
Unknown
Size
21 KB
Referenced Files
None
Subscribers
None
irc_window.as
View Options
import
elements.BaseGuiElement
;
import
elements.GuiDraggable
;
import
elements.GuiPanel
;
import
elements.GuiTextbox
;
import
elements.GuiText
;
import
elements.GuiButton
;
import
elements.GuiBackgroundPanel
;
import
elements.GuiMarkupText
;
import
elements.GuiResizeHandle
;
import
elements.MarkupTooltip
;
import
dialogs.InputDialog
;
import
version
;
#
include
"dialogs/include/UniqueDialogs.as"
#
section
gui
from
tabs
.
WikiTab
import
showWikiPage
,
openGeneralLink
;
void
openWiki
(
const
string
&
link
,
int
button
)
{
if
(
button
==
0
)
showWikiPage
(
link
,
false
);
else
if
(
button
==
2
)
showWikiPage
(
link
,
true
);
}
#
section
menu
void
openWiki
(
const
string
&
link
,
int
button
)
{
if
(
button
==
0
)
openBrowser
(
format
(
"http://wiki.starruler2.com/$1"
,
link
.
replaced
(
" "
,
"_"
)));
}
void
openGeneralLink
(
const
string
&
link
,
int
button
=
0
)
{
if
(
link
.
findFirst
(
URI_HINT
)
!=
-
1
)
{
if
(
button
==
0
)
openBrowser
(
link
);
}
else
{
openWiki
(
link
,
button
);
}
}
#
section
all
const
uint
SENDER_WIDTH
=
110
;
const
string
URI_HINT
=
"://"
;
const
string
LEFT_BRACKET
=
"["
;
const
double
FLASH_TIME
=
1.0
;
const
array
<
Color
>
NICK_COLORS
=
{
Color
(
0x759ca6ff
),
Color
(
0x8675a6ff
),
Color
(
0xa87590ff
),
Color
(
0xa67577ff
),
Color
(
0x7da675ff
),
Color
(
0x75a685ff
)
};
enum
Dialogs
{
D_ChangeNick
,
};
class
ChangeNick
:
InputDialogCallback
{
void
inputCallback
(
InputDialog
@
dialog
,
bool
accepted
)
{
if
(
accepted
)
{
string
name
=
dialog
.
getTextInput
(
0
);
IRC
.
nickname
=
name
;
settings
::
sNickname
=
name
;
saveSettings
();
}
}
};
class
LinkableMarkupText
:
GuiMarkupText
{
LinkableMarkupText
(
IGuiElement
@
parent
,
const
recti
&
pos
)
{
super
(
parent
,
pos
);
@
tooltipObject
=
MarkupTooltip
(
400
,
0
.
f
,
true
,
true
);
}
void
onLinkClicked
(
const
string
&
link
,
int
button
)
override
{
openGeneralLink
(
link
,
button
);
}
};
bool
isNickBold
(
const
string
&
nick
)
{
if
(
nick
.
length
==
0
)
return
false
;
return
nick
==
"GGLucas"
||
nick
==
"ThyReaper"
||
nick
==
"Firgof"
||
nick
==
"*"
||
nick
[
0
]
==
'@'
;
}
Color
getNickColor
(
const
string
&
nick
)
{
uint8
amt
=
0
;
for
(
uint
i
=
0
,
cnt
=
nick
.
length
;
i
<
cnt
;
++
i
)
amt
+=
uint8
(
nick
[
i
]);
return
NICK_COLORS
[
amt
%
NICK_COLORS
.
length
];
}
uint
missedMessages
=
0
;
void
updateHighlights
(
IRCChannel
@
chan
,
const
string
&
myNick
)
{
Lock
lock
(
chan
.
mutex
);
uint
msgCount
=
chan
.
messageCount
;
bool
isPM
=
chan
.
isPM
;
for
(
uint
i
=
0
;
i
<
msgCount
;
++
i
)
{
IRCMessageType
type
=
chan
.
message_types
[
i
];
if
(
type
==
IMT_Action
||
type
==
IMT_Message
)
{
uint
id
=
chan
.
message_ids
[
i
];
if
(
id
>
chan
.
handledId
)
{
bool
highlight
=
false
;
if
(
isPM
)
{
highlight
=
true
;
}
else
{
string
msg
=
chan
.
messages
[
i
];
highlight
=
msg
.
contains_nocase
(
myNick
);
}
if
(
highlight
)
{
sound
::
notify
.
play
(
priority
=
true
);
if
(
window
is
null
||
!
window
.
visible
)
ircButton
.
flash
();
if
(
window
is
null
||
window
.
activeChannel
!
is
chan
)
chan
.
highlight
=
true
;
}
if
(
window
is
null
||
!
window
.
visible
)
++
missedMessages
;
chan
.
handledId
=
id
;
}
}
}
}
class
ChannelDisplay
:
BaseGuiElement
{
array
<
string
>
senders
;
array
<
string
>
messages
;
array
<
LinkableMarkupText
@
>
markups
;
array
<
bool
>
nicksBold
;
array
<
bool
>
isHighlight
;
array
<
Color
>
nickColors
;
string
lastChan
;
uint
prevId
=
0
;
ChannelDisplay
(
IGuiElement
@
parent
)
{
super
(
parent
,
recti
(
0
,
0
,
20
,
20
));
updateAbsolutePosition
();
}
void
updateAbsolutePosition
()
override
{
int
w
=
parent
.
updatePosition
.
width
;
if
(
w
>=
720
)
w
-=
120
;
size
=
vec2i
(
w
,
max
(
20
,
size
.
height
));
BaseGuiElement
::
updateAbsolutePosition
();
}
void
update
(
IRCChannel
@
chan
)
{
chan
.
highlight
=
false
;
uint
msgCount
=
chan
.
messageCount
;
if
(
chan
.
messageId
!=
prevId
||
msgCount
!=
messages
.
length
||
chan
.
name
!=
lastChan
)
{
lastChan
=
chan
.
name
;
messages
.
length
=
msgCount
;
senders
.
length
=
msgCount
;
nicksBold
.
length
=
msgCount
;
nickColors
.
length
=
msgCount
;
isHighlight
.
length
=
msgCount
;
prevId
=
chan
.
messageId
;
string
myNick
=
IRC
.
nickname
;
uint
prevMarkups
=
markups
.
length
;
for
(
uint
i
=
msgCount
;
i
<
prevMarkups
;
++
i
)
{
if
(
markups
[
i
]
!
is
null
)
{
markups
[
i
].
remove
();
@
markups
[
i
]
=
null
;
}
}
markups
.
length
=
msgCount
;
{
Lock
lock
(
chan
.
mutex
);
for
(
uint
i
=
0
;
i
<
msgCount
;
++
i
)
{
IRCMessageType
type
=
chan
.
message_types
[
i
];
string
sender
=
chan
.
message_senders
[
i
];
uint8
sender_type
=
chan
.
message_sender_types
[
i
];
uint
id
=
chan
.
message_ids
[
i
];
nickColors
[
i
]
=
getNickColor
(
sender
);
string
msg
=
chan
.
messages
[
i
];
if
(
type
==
IMT_Action
||
type
==
IMT_Message
)
isHighlight
[
i
]
=
msg
.
contains_nocase
(
myNick
);
else
isHighlight
[
i
]
=
false
;
bool
needMarkup
=
msg
.
findFirst
(
LEFT_BRACKET
)
!=
-
1
;
if
(
sender_type
!=
'@'
&&
sender_type
!=
'+'
)
{
if
(
needMarkup
)
msg
=
bbescape
(
msg
,
allowWikiLinks
=
true
);
}
switch
(
type
)
{
case
IMT_Join
:
senders
[
i
]
=
"*"
;
msg
=
format
(
locale
::
IRC_JOIN
,
sender
,
chan
.
name
,
toString
(
nickColors
[
i
]));
needMarkup
=
true
;
break
;
case
IMT_Part
:
senders
[
i
]
=
"*"
;
msg
=
format
(
locale
::
IRC_PART
,
sender
,
chan
.
name
,
toString
(
nickColors
[
i
]));
needMarkup
=
true
;
break
;
case
IMT_Quit
:
senders
[
i
]
=
"*"
;
msg
=
format
(
locale
::
IRC_QUIT
,
sender
,
msg
,
toString
(
nickColors
[
i
]));
needMarkup
=
true
;
break
;
case
IMT_Action
:
senders
[
i
]
=
"*"
;
msg
=
format
(
locale
::
IRC_ACTION
,
sender
,
msg
,
toString
(
nickColors
[
i
]));
needMarkup
=
true
;
break
;
case
IMT_Nick
:
senders
[
i
]
=
"*"
;
msg
=
format
(
locale
::
IRC_NICK
,
sender
,
msg
,
toString
(
nickColors
[
i
]),
toString
(
getNickColor
(
msg
)));
needMarkup
=
true
;
break
;
case
IMT_Kick
:
senders
[
i
]
=
"*"
;
msg
=
format
(
locale
::
IRC_KICK
,
sender
,
msg
,
toString
(
nickColors
[
i
]),
toString
(
getNickColor
(
msg
)));
needMarkup
=
true
;
break
;
case
IMT_Topic
:
senders
[
i
]
=
"*"
;
msg
=
format
(
locale
::
IRC_TOPIC
,
sender
,
msg
,
toString
(
nickColors
[
i
]));
needMarkup
=
true
;
break
;
case
IMT_Mode
:
senders
[
i
]
=
"*"
;
msg
=
format
(
locale
::
IRC_MODE
,
sender
,
msg
,
toString
(
nickColors
[
i
]));
needMarkup
=
true
;
break
;
case
IMT_UMode
:
senders
[
i
]
=
"*"
;
msg
=
format
(
locale
::
IRC_UMODE
,
sender
,
msg
,
toString
(
nickColors
[
i
]));
needMarkup
=
true
;
break
;
case
IMT_TopicIs
:
senders
[
i
]
=
"*"
;
msg
=
format
(
locale
::
IRC_TOPIC_IS
,
chan
.
name
,
msg
,
toString
(
nickColors
[
i
]));
break
;
case
IMT_Disconnect
:
senders
[
i
]
=
"*"
;
msg
=
locale
::
IRC_DISCONNECT
;
needMarkup
=
true
;
break
;
default
:
{
if
(
sender_type
!=
' '
)
{
senders
[
i
]
=
" "
+
sender
;
senders
[
i
][
0
]
=
sender_type
;
}
else
{
senders
[
i
]
=
sender
;
}
}
break
;
}
bool
hasLinks
=
msg
.
findFirst
(
URI_HINT
)
!=
-
1
;
if
(
hasLinks
)
{
msg
=
makebbLinks
(
msg
);
needMarkup
=
true
;
}
messages
[
i
]
=
msg
;
nicksBold
[
i
]
=
isNickBold
(
senders
[
i
]);
auto
@
elem
=
markups
[
i
];
if
(
needMarkup
)
{
if
(
elem
is
null
)
{
@
elem
=
LinkableMarkupText
(
this
,
recti_area
(
0
,
0
,
size
.
width
-
SENDER_WIDTH
-
27
,
20
));
@
markups
[
i
]
=
elem
;
}
elem
.
text
=
msg
;
elem
.
updateAbsolutePosition
();
}
else
{
if
(
elem
!
is
null
)
{
elem
.
remove
();
@
markups
[
i
]
=
null
;
}
}
}
}
}
}
void
draw
()
override
{
const
Font
@
ft
=
skin
.
getFont
(
FT_Normal
);
const
Font
@
bold
=
skin
.
getFont
(
FT_Bold
);
recti
leftPos
=
recti_area
(
AbsolutePosition
.
topLeft
+
vec2i
(
4
,
6
),
vec2i
(
SENDER_WIDTH
,
20
));
recti
rightPos
=
recti_area
(
AbsolutePosition
.
topLeft
+
vec2i
(
SENDER_WIDTH
+
13
,
7
),
vec2i
(
size
.
width
-
SENDER_WIDTH
-
27
,
20
));
uint
msgCount
=
messages
.
length
;
vec2i
npos
;
for
(
uint
i
=
0
;
i
<
msgCount
;
++
i
)
{
if
(
isHighlight
[
i
])
drawRectangle
(
leftPos
,
Color
(
0xff888820
));
if
(
nicksBold
[
i
])
bold
.
draw
(
leftPos
,
senders
[
i
],
locale
::
ELLIPSIS
,
nickColors
[
i
],
1.0
,
0.5
);
else
ft
.
draw
(
leftPos
,
senders
[
i
],
locale
::
ELLIPSIS
,
nickColors
[
i
],
1.0
,
0.5
);
auto
@
elem
=
markups
[
i
];
if
(
elem
is
null
)
{
npos
=
ft
.
draw
(
rightPos
,
vec2i
(),
20
,
messages
[
i
],
Color
(
0xffffffff
),
true
);
}
else
{
vec2i
markupSize
=
elem
.
size
;
elem
.
size
=
vec2i
(
size
.
width
-
SENDER_WIDTH
-
27
,
markupSize
.
y
);
elem
.
position
=
rightPos
.
topLeft
-
AbsolutePosition
.
topLeft
-
vec2i
(
0
,
1
);
npos
=
vec2i
(
rightPos
.
topLeft
.
x
,
rightPos
.
topLeft
.
y
+
markupSize
.
y
);
}
int
ydiff
=
npos
.
y
-
rightPos
.
topLeft
.
y
;
if
(
npos
.
x
>
rightPos
.
topLeft
.
x
)
ydiff
+=
20
;
leftPos
+=
vec2i
(
0
,
ydiff
);
rightPos
+=
vec2i
(
0
,
ydiff
);
}
int
needHeight
=
max
(
rightPos
.
topLeft
.
y
-
AbsolutePosition
.
topLeft
.
y
,
20
);
if
(
size
.
height
!=
needHeight
)
{
size
=
vec2i
(
parent
.
updatePosition
.
width
,
needHeight
);
//Hax
GuiPanel
@
par
=
cast
<
GuiPanel
>(
parent
);
bool
wasBottom
=
par
.
vert
.
pos
>=
(
par
.
vert
.
end
-
par
.
vert
.
page
);
par
.
updateAbsolutePosition
();
if
(
wasBottom
)
{
par
.
vert
.
pos
=
max
(
0.0
,
par
.
vert
.
end
-
par
.
vert
.
page
);
par
.
updateAbsolutePosition
();
}
}
BaseGuiElement
::
draw
();
}
};
class
ChanButton
:
GuiButton
{
IRCChannel
@
channel
;
ChanButton
(
IGuiElement
@
parent
)
{
super
(
parent
,
recti
());
}
};
class
IRCInput
:
GuiTextbox
{
IRCWindow
@
window
;
IRCInput
(
IRCWindow
@
win
,
Alignment
@
align
)
{
@
window
=
win
;
super
(
win
,
align
);
}
bool
onKeyEvent
(
const
KeyboardEvent
&
event
,
IGuiElement
@
source
)
{
if
(
event
.
type
==
KET_Key_Down
)
{
if
(
event
.
key
==
KEY_TAB
)
{
return
true
;
}
}
else
if
(
event
.
type
==
KET_Key_Up
)
{
if
(
event
.
key
==
KEY_TAB
)
{
tabComplete
();
return
true
;
}
}
return
GuiTextbox
::
onKeyEvent
(
event
,
source
);
}
void
tabComplete
()
{
if
(
Text
.
length
==
0
)
return
;
//Get word before cursor
string
before
;
IRCChannel
@
chan
=
window
.
activeChannel
;
int
pos
=
curs
-
1
;
for
(;
pos
>
0
;
--
pos
)
{
if
(
Text
[
pos
]
==
' '
)
{
++
pos
;
break
;
}
}
if
(
pos
>=
0
&&
pos
<
curs
)
before
=
Text
.
substr
(
pos
,
curs
-
pos
);
else
if
(
pos
>
0
)
return
;
//Find nickname in opposite direction of use.
string
found
;
for
(
int
i
=
window
.
disp
.
senders
.
length
-
1
;
i
>=
0
;
--
i
)
{
string
compare
=
window
.
disp
.
senders
[
i
].
substr
(
1
);
if
((
before
.
length
==
0
||
compare
.
startswith_nocase
(
before
))
&&
compare
.
length
>
1
)
{
found
=
compare
;
break
;
}
}
//No nickname found, try user list
if
(
found
.
length
==
0
)
{
for
(
uint
i
=
0
,
cnt
=
window
.
activeUsers
.
length
;
i
<
cnt
;
++
i
)
{
string
compare
=
window
.
activeUsers
[
i
].
substr
(
1
);
if
(
compare
.
startswith_nocase
(
before
))
{
found
=
compare
;
break
;
}
}
}
//Append to textbox
if
(
found
.
length
!=
0
)
{
if
(
pos
>
0
)
Text
=
Text
.
substr
(
0
,
pos
);
else
Text
=
""
;
Text
+=
found
;
if
(
pos
<=
0
)
Text
+=
": "
;
else
Text
+=
" "
;
curs
=
Text
.
length
;
}
}
void
remove
()
{
@
window
=
null
;
GuiTextbox
::
remove
();
}
}
class
IRCWindow
:
GuiDraggable
{
GuiBackgroundPanel
@
bg
;
GuiPanel
@
panel
;
ChannelDisplay
@
disp
;
GuiTextbox
@
messageBox
;
GuiButton
@
nickButton
;
GuiButton
@
closeButton
;
GuiResizeHandle
@
handle
;
BaseGuiElement
@
chanList
;
array
<
ChanButton
@
>
chanButtons
;
IRCChannel
@
activeChannel
;
array
<
string
>
activeUsers
;
array
<
string
>
userMarks
;
array
<
string
>
usersCut
;
array
<
Color
>
userColors
;
array
<
bool
>
usersBold
;
GuiSkinElement
@
userBG
;
GuiPanel
@
userPanel
;
BaseGuiElement
@
userList
;
string
prevUsers
;
IRCWindow
()
{
super
(
null
,
IRC
.
display
);
visible
=
IRC
.
display
.
width
!=
0
;
@
bg
=
GuiBackgroundPanel
(
this
,
Alignment_Fill
());
bg
.
titleColor
=
Color
(
0xb3fe00ff
);
@
handle
=
GuiResizeHandle
(
this
,
Alignment
(
Right
-
12
,
Bottom
-
12
,
Right
,
Bottom
));
handle
.
minSize
=
vec2i
(
450
,
200
);
@
nickButton
=
GuiButton
(
bg
,
Alignment
(
Right
-
185
,
Top
+
3
,
Right
-
33
,
Top
+
28
));
nickButton
.
visible
=
false
;
@
closeButton
=
GuiButton
(
bg
,
Alignment
(
Right
-
31
,
Top
+
3
,
Right
-
5
,
Top
+
28
),
"X"
);
@
panel
=
GuiPanel
(
this
,
Alignment
(
Left
+
10
,
Top
+
32
,
Right
-
10
,
Bottom
-
44
));
@
chanList
=
BaseGuiElement
(
this
,
Alignment
(
Left
+
10
,
Bottom
-
70
,
Right
-
10
,
Bottom
-
44
));
chanList
.
visible
=
false
;
@
disp
=
ChannelDisplay
(
panel
);
@
messageBox
=
IRCInput
(
this
,
Alignment
(
Left
+
10
,
Bottom
-
40
,
Right
-
10
,
Bottom
-
10
));
@
userBG
=
GuiSkinElement
(
this
,
Alignment
(
Right
-
150
,
Top
+
34
,
Right
-
10
,
Bottom
-
44
),
SS_LightPanel
);
@
userPanel
=
GuiPanel
(
userBG
,
Alignment
().
fill
());
userPanel
.
horizType
=
ST_Never
;
@
userList
=
BaseGuiElement
(
userPanel
,
recti
(
0
,
0
,
140
,
20
));
userBG
.
visible
=
false
;
updateAbsolutePosition
();
}
void
remove
()
override
{
GuiDraggable
::
remove
();
}
void
updateAbsolutePosition
()
{
if
(
panel
!
is
null
)
{
bool
showUsers
=
size
.
width
>=
750
&&
(
activeChannel
!
is
null
&&
!
activeChannel
.
isPM
);
if
(
showUsers
)
{
panel
.
alignment
.
right
.
pixels
=
160
;
userBG
.
visible
=
true
;
}
else
{
panel
.
alignment
.
right
.
pixels
=
10
;
userBG
.
visible
=
false
;
}
}
GuiDraggable
::
updateAbsolutePosition
();
}
void
updateUsers
()
{
if
(
activeChannel
is
null
)
return
;
activeChannel
.
getUsers
(
activeUsers
);
activeUsers
.
sortDesc
();
uint
userCnt
=
activeUsers
.
length
;
usersCut
.
length
=
userCnt
;
userMarks
.
length
=
userCnt
;
usersBold
.
length
=
userCnt
;
userColors
.
length
=
userCnt
;
for
(
uint
i
=
0
;
i
<
userCnt
;
++
i
)
{
usersCut
[
i
]
=
activeUsers
[
i
].
substr
(
1
);
userMarks
[
i
]
=
activeUsers
[
i
].
substr
(
0
,
1
);
usersBold
[
i
]
=
isNickBold
(
activeUsers
[
i
]);
userColors
[
i
]
=
getNickColor
(
usersCut
[
i
]);
}
int
h
=
userCnt
*
24
;
if
(
h
!=
userList
.
size
.
height
)
{
userList
.
size
=
vec2i
(
140
,
h
);
userPanel
.
updateAbsolutePosition
();
}
}
void
draw
()
{
GuiDraggable
::
draw
();
if
(
userBG
.
visible
)
{
const
Font
@
font
=
skin
.
getFont
(
FT_Normal
);
vec2i
pos
=
userList
.
AbsolutePosition
.
topLeft
+
vec2i
(
6
,
6
);
int
start
=
userBG
.
absolutePosition
.
topLeft
.
y
;
int
end
=
userBG
.
absolutePosition
.
botRight
.
y
;
setClip
(
userBG
.
absoluteClipRect
);
int
w
=
130
;
if
(
userPanel
.
vert
.
visible
)
w
-=
20
;
for
(
uint
i
=
0
,
cnt
=
activeUsers
.
length
;
i
<
cnt
;
++
i
)
{
if
(
pos
.
y
<
start
-
20
||
pos
.
y
>
end
)
{
pos
.
y
+=
20
;
continue
;
}
Color
col
=
userColors
[
i
];
const
Font
@
ft
=
font
;
if
(
usersBold
[
i
]
&&
ft
.
bold
!
is
null
)
@
ft
=
ft
.
bold
;
ft
.
draw
(
pos
=
recti_area
(
pos
,
vec2i
(
14
,
20
)),
text
=
userMarks
[
i
],
color
=
col
,
ellipsis
=
locale
::
SHORT_ELLIPSIS
,
horizAlign
=
1.0
);
ft
.
draw
(
pos
=
recti_area
(
pos
+
vec2i
(
15
,
0
),
vec2i
(
w
-
15
,
20
)),
text
=
usersCut
[
i
],
ellipsis
=
locale
::
ELLIPSIS
,
color
=
col
);
pos
.
y
+=
20
;
}
}
}
void
update
(
double
time
)
{
if
(
visible
)
{
IRC
.
display
=
rect
;
prevSize
=
rect
;
missedMessages
=
0
;
}
else
{
IRC
.
display
=
recti
();
}
if
(!
IRC
.
connected
)
return
;
if
(
IRC
.
channelCount
==
0
)
{
IRC
.
join
(
"#starruler"
);
return
;
}
if
(
activeChannel
is
null
||
activeChannel
.
closed
)
setActiveChannel
(
IRC
.
channels
[
0
]);
Lock
lock
(
IRC
.
mutex
);
if
(
visible
)
{
//Update window elements
if
(
activeChannel
!
is
null
)
bg
.
title
=
activeChannel
.
topic
;
nickButton
.
text
=
format
(
locale
::
IRC_NICKNAME
,
IRC
.
nickname
);
nickButton
.
visible
=
true
;
//Update the active channel
if
(
activeChannel
.
messageId
!=
disp
.
prevId
||
activeChannel
.
getUserCount
()
!=
activeUsers
.
length
)
updateUsers
();
disp
.
update
(
activeChannel
);
//Update the channel list buttons
uint
chanCnt
=
IRC
.
channelCount
;
if
(
chanCnt
>
1
)
{
chanList
.
visible
=
true
;
panel
.
alignment
.
bottom
.
pixels
=
74
;
uint
oldCnt
=
chanButtons
.
length
;
uint
newCnt
=
chanCnt
;
for
(
uint
i
=
newCnt
;
i
<
oldCnt
;
++
i
)
chanButtons
[
i
].
remove
();
chanButtons
.
length
=
newCnt
;
for
(
uint
i
=
oldCnt
;
i
<
newCnt
;
++
i
)
{
@
chanButtons
[
i
]
=
ChanButton
(
chanList
);
chanButtons
[
i
].
toggleButton
=
true
;
}
int
x
=
0
;
int
h
=
chanList
.
size
.
height
;
int
w
=
chanList
.
size
.
width
;
if
(
userBG
.
visible
)
w
-=
150
;
w
=
min
(
160
,
w
/
chanCnt
);
for
(
uint
i
=
0
;
i
<
chanCnt
;
++
i
)
{
IRCChannel
@
chan
=
IRC
.
channels
[
i
];
@
chanButtons
[
i
].
channel
=
chan
;
chanButtons
[
i
].
text
=
chan
.
name
;
chanButtons
[
i
].
pressed
=
chan
is
activeChannel
;
if
(
chan
.
highlight
)
chanButtons
[
i
].
color
=
Color
(
0xff8000ff
);
else
chanButtons
[
i
].
color
=
Color
(
0xffffffff
);
chanButtons
[
i
].
size
=
vec2i
(
w
,
h
);
chanButtons
[
i
].
position
=
vec2i
(
x
,
0
);
x
+=
w
;
}
}
else
{
chanList
.
visible
=
false
;
panel
.
alignment
.
bottom
.
pixels
=
44
;
uint
oldCnt
=
chanButtons
.
length
;
for
(
uint
i
=
0
;
i
<
oldCnt
;
++
i
)
chanButtons
[
i
].
remove
();
chanButtons
.
length
=
0
;
}
}
//Update highlights
{
string
myNick
=
IRC
.
nickname
;
uint
chanCnt
=
IRC
.
channelCount
;
for
(
uint
i
=
0
;
i
<
chanCnt
;
++
i
)
updateHighlights
(
IRC
.
channels
[
i
],
myNick
);
}
}
void
promptNickChange
()
{
if
(
focusDialog
(
D_ChangeNick
))
return
;
InputDialog
@
dialog
=
InputDialog
(
ChangeNick
(),
this
);
dialog
.
accept
.
text
=
locale
::
CHANGE_NICK
;
dialog
.
addTextInput
(
locale
::
NICKNAME
,
IRC
.
nickname
);
addDialog
(
D_ChangeNick
,
dialog
);
dialog
.
focusInput
();
}
bool
onMouseEvent
(
const
MouseEvent
&
event
,
IGuiElement
@
source
)
{
switch
(
event
.
type
)
{
case
MET_Button_Up
:
if
(
handle
.
dragging
)
handle
.
dragging
=
false
;
setGuiFocus
(
messageBox
);
break
;
}
return
GuiDraggable
::
onMouseEvent
(
event
,
source
);
}
void
setActiveChannel
(
IRCChannel
@
chan
)
{
@
activeChannel
=
chan
;
bool
showUsers
=
size
.
width
>=
750
&&
(
chan
!
is
null
&&
!
chan
.
isPM
);
if
(
showUsers
!=
userBG
.
visible
)
updateAbsolutePosition
();
}
bool
onGuiEvent
(
const
GuiEvent
&
evt
)
override
{
if
(
evt
.
caller
is
messageBox
)
{
if
(
evt
.
type
==
GUI_Confirmed
)
{
if
(
activeChannel
is
null
)
return
true
;
IRC
.
send
(
activeChannel
,
messageBox
.
text
);
messageBox
.
clear
();
return
true
;
}
}
else
if
(
evt
.
caller
is
closeButton
)
{
if
(
evt
.
type
==
GUI_Clicked
)
{
visible
=
false
;
return
true
;
}
}
else
if
(
evt
.
caller
is
nickButton
)
{
if
(
evt
.
type
==
GUI_Clicked
)
{
promptNickChange
();
return
true
;
}
}
else
if
(
evt
.
type
==
GUI_Clicked
)
{
ChanButton
@
but
=
cast
<
ChanButton
>(
evt
.
caller
);
if
(
but
!
is
null
)
setActiveChannel
(
but
.
channel
);
}
return
GuiDraggable
::
onGuiEvent
(
evt
);
}
};
IRCWindow
@
window
;
IRCButton
@
ircButton
;
recti
prevSize
;
void
openIRC
()
{
IRC
.
display
=
recti_centered
(
recti
(
vec2i
(
0
,
0
),
screenSize
),
vec2i
(
750
,
500
));
if
(
window
is
null
)
@
window
=
IRCWindow
();
}
void
closeIRC
()
{
if
(
window
!
is
null
)
window
.
visible
=
false
;
IRC
.
display
=
recti
();
}
void
showIRC
()
{
if
(!
IRC
.
running
)
{
IRC
.
nickname
=
settings
::
sNickname
;
IRC
.
connect
();
openIRC
();
}
else
{
if
(
window
is
null
)
{
openIRC
();
}
else
{
window
.
visible
=
!
window
.
visible
;
if
(!
window
.
visible
)
{
IRC
.
display
=
recti
();
}
else
if
(
IRC
.
display
.
width
==
0
)
{
if
(
prevSize
.
width
!=
0
)
IRC
.
display
=
prevSize
;
else
IRC
.
display
=
recti_centered
(
recti
(
vec2i
(
0
,
0
),
screenSize
),
vec2i
(
750
,
500
));
window
.
rect
=
IRC
.
display
;
}
}
}
}
class
IRCButtonEvent
:
onButtonClick
{
bool
onClick
(
GuiButton
@
btn
)
{
ircButton
.
flashes
=
0
;
IRC
.
highlight
=
false
;
if
(
window
is
null
)
{
openIRC
();
}
else
{
window
.
visible
=
!
window
.
visible
;
if
(!
window
.
visible
)
{
IRC
.
display
=
recti
();
}
else
if
(
IRC
.
display
.
width
==
0
)
{
if
(
prevSize
.
width
!=
0
)
IRC
.
display
=
prevSize
;
else
IRC
.
display
=
recti_centered
(
recti
(
vec2i
(
0
,
0
),
screenSize
),
vec2i
(
750
,
500
));
window
.
rect
=
IRC
.
display
;
}
}
return
true
;
}
};
class
ChangeNickCommand
:
ConsoleCommand
{
void
execute
(
const
string
&
args
)
{
string
name
=
args
;
IRC
.
nickname
=
name
;
settings
::
sNickname
=
name
;
saveSettings
();
}
};
class
IRCButton
:
GuiButton
{
int
flashes
=
0
;
double
flashTime
=
0
;
GuiText
@
missed
;
IRCButton
(
Alignment
@
align
)
{
super
(
null
,
align
);
spriteStyle
=
Sprite
(
material
::
IRCButton
);
visible
=
false
;
@
missed
=
GuiText
(
this
,
Alignment
().
padded
(
4
));
missed
.
horizAlign
=
1.0
;
missed
.
vertAlign
=
0.6
;
missed
.
stroke
=
colors
::
Black
;
missed
.
color
=
Color
(
0xff8000ff
);
missed
.
font
=
FT_Bold
;
}
void
flash
()
{
flashes
+=
3
;
IRC
.
highlight
=
true
;
}
void
draw
()
{
//Show flashes
if
(
flashTime
>
0.0
)
{
float
pct
=
0
.
f
;
if
(
flashTime
<
FLASH_TIME
*
0.5
)
pct
=
1
.
f
-
(
FLASH_TIME
*
0.5
-
flashTime
)
/
(
FLASH_TIME
*
0.5
);
else
pct
=
1
.
f
-
(
flashTime
-
FLASH_TIME
*
0.5
)
/
(
FLASH_TIME
*
0.5
);
color
=
Color
(
0xffaaaaff
).
interpolate
(
Color
(
0xff8000ff
),
pct
);
flashTime
-=
frameLength
;
}
else
{
if
(
flashes
>
0
)
{
--
flashes
;
flashTime
=
FLASH_TIME
;
}
if
(
IRC
.
highlight
)
color
=
Color
(
0xffaaaaff
);
else
color
=
colors
::
White
;
}
if
(
missedMessages
!=
0
)
{
missed
.
text
=
toString
(
missedMessages
);
missed
.
visible
=
true
;
}
else
{
missed
.
visible
=
false
;
}
GuiButton
::
draw
();
}
};
void
init
()
{
#
section
game
@
ircButton
=
IRCButton
(
Alignment
(
Right
-
32
,
Top
+
20
,
Width
=
32
,
Height
=
64
));
#
section
menu
@
ircButton
=
IRCButton
(
Alignment
(
Right
-
32
,
Top
+
100
,
Width
=
32
,
Height
=
64
));
setNickname
(
settings
::
sNickname
);
addConsoleCommand
(
"nick"
,
ChangeNickCommand
());
string
ver
=
SCRIPT_VERSION
;
int
pos
=
ver
.
findLast
(
" "
);
if
(
pos
!=
-
1
)
ver
=
ver
.
substr
(
pos
+
1
);
IRC_HOSTNAME
=
"SR2"
+
ArchName
+
ArchBits
+
ver
;
if
(
cloud
::
isActive
)
IRC_HOSTNAME
+=
"S"
;
if
(!
IS_STEAM_BUILD
)
IRC_HOSTNAME
+=
"G"
;
if
(
hasDLC
(
"Heralds"
))
IRC_HOSTNAME
+=
"H"
;
#
section
all
@
ircButton
.
onClick
=
IRCButtonEvent
();
}
void
onGameStateChange
()
{
if
(
window
!
is
null
)
{
if
(
IRC
.
display
.
width
==
0
)
{
window
.
visible
=
false
;
}
else
{
window
.
rect
=
IRC
.
display
;
window
.
visible
=
true
;
}
window
.
update
(
1.0
);
}
}
void
tick
(
double
time
)
{
#
section
menu
if
(
game_state
!=
GS_Menu
)
return
;
#
section
gui
if
(
game_state
!=
GS_Game
)
return
;
#
section
all
if
(
IRC
.
running
)
{
if
(!
ircButton
.
visible
)
{
ircButton
.
visible
=
true
;
if
(
window
is
null
)
@
window
=
IRCWindow
();
}
ircButton
.
bringToFront
();
}
else
{
if
(
ircButton
.
visible
)
ircButton
.
visible
=
false
;
if
(
window
!
is
null
&&
window
.
visible
)
window
.
visible
=
false
;
}
if
(
window
!
is
null
)
window
.
update
(
time
);
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sun, Nov 15, 4:59 PM (1 d, 20 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
135800
Default Alt Text
irc_window.as (21 KB)
Attached To
Mode
R80 StarRuler2-Source
Attached
Detach File
Event Timeline