Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Khanat code
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Tycho Brahe
Khanat code
Commits
2e5bcdf2
Commit
2e5bcdf2
authored
Jan 21, 2017
by
Nimetu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added: Clickable urls in chat text (issue 282)
parent
b9ab826f
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
334 additions
and
26 deletions
+334
-26
code/ryzom/client/data/gamedev/interfaces_v3/interaction.lua
code/ryzom/client/data/gamedev/interfaces_v3/interaction.lua
+14
-0
code/ryzom/client/data/gamedev/interfaces_v3/interaction.xml
code/ryzom/client/data/gamedev/interfaces_v3/interaction.xml
+15
-0
code/ryzom/client/src/interface_v3/chat_text_manager.cpp
code/ryzom/client/src/interface_v3/chat_text_manager.cpp
+299
-25
code/ryzom/client/src/interface_v3/chat_text_manager.h
code/ryzom/client/src/interface_v3/chat_text_manager.h
+6
-1
No files found.
code/ryzom/client/data/gamedev/interfaces_v3/interaction.lua
View file @
2e5bcdf2
...
...
@@ -537,3 +537,17 @@ function game:openWebIGBrowserHeader()
ui
.
w
=
ui_webig_browser_w
;
end
end
------------------------------------------------------------------------------------------------------------
local
SavedUrl
=
""
;
function
game
:
chatUrl
(
url
)
SavedUrl
=
url
runAH
(
nil
,
"active_menu"
,
"menu=ui:interface:chat_uri_action_menu"
);
end
function
game
:
chatUrlCopy
()
runAH
(
nil
,
"copy_to_clipboard"
,
SavedUrl
)
end
function
game
:
chatUrlBrowse
()
runAH
(
nil
,
"browse"
,
"name=ui:interface:webig:content:html|url="
..
SavedUrl
)
end
code/ryzom/client/data/gamedev/interfaces_v3/interaction.xml
View file @
2e5bcdf2
...
...
@@ -3127,4 +3127,19 @@
<action
handler=
"set"
params=
"dblink=UI:SAVE:ISDETACHED:DYNAMIC_CHAT@0|value=0"
/>
</proc>
<!-- there seems to be no way to pass url to menu, use lua script for middleman -->
<group
type=
"menu"
id=
"chat_uri_action_menu"
extends=
"base_menu"
>
<action
id=
"copy"
name=
"uiCopy"
handler=
"lua"
params=
"game:chatUrlCopy()"
/>
<action
id=
"openig"
name=
"uiBrowse"
handler=
"lua"
params=
"game:chatUrlBrowse()"
/>
</group>
</interface_config>
code/ryzom/client/src/interface_v3/chat_text_manager.cpp
View file @
2e5bcdf2
...
...
@@ -20,6 +20,7 @@
// client
#include "chat_text_manager.h"
#include "nel/gui/view_text.h"
#include "nel/gui/group_paragraph.h"
#include "interface_manager.h"
using
namespace
std
;
...
...
@@ -149,34 +150,165 @@ static CInterfaceGroup *buildLineWithCommand(CInterfaceGroup *commandGroup, CVie
return
group
;
}
//=================================================================================
CViewBase
*
CChatTextManager
::
createMsgText
(
const
ucstring
&
cstMsg
,
NLMISC
::
CRGBA
col
,
bool
justified
/*=false*/
)
static
inline
bool
isUrlTag
(
const
ucstring
&
s
,
ucstring
::
size_type
index
,
ucstring
::
size_type
textSize
)
{
ucstring
msg
=
cstMsg
;
CInterfaceGroup
*
commandGroup
=
parseCommandTag
(
msg
);
CViewText
*
vt
=
new
CViewText
(
CViewText
::
TCtorParam
());
// get parameters from config.xml
vt
->
setShadow
(
isTextShadowed
());
vt
->
setShadowOutline
(
false
);
vt
->
setFontSize
(
getTextFontSize
());
vt
->
setMultiLine
(
true
);
vt
->
setTextMode
(
justified
?
CViewText
::
Justified
:
CViewText
::
DontClipWord
);
vt
->
setMultiLineSpace
(
getTextMultiLineSpace
());
vt
->
setModulateGlobalColor
(
false
);
// Format http://, https://
// or markdown style (title)[http://..]
if
(
textSize
>
index
+
7
)
{
bool
markdown
=
false
;
ucstring
::
size_type
i
=
index
;
// advance index to url section if markdown style link is detected
if
(
s
[
i
]
==
'('
)
{
// scan for ')[http://'
while
(
i
<
textSize
-
9
)
{
if
(
s
[
i
]
==
')'
&&
s
[
i
+
1
]
==
'['
)
{
i
+=
2
;
markdown
=
true
;
break
;
}
else
if
(
s
[
i
]
==
')'
)
{
i
+=
1
;
break
;
}
i
++
;
}
}
ucstring
cur_time
;
if
(
showTimestamps
())
if
(
textSize
>
i
+
7
)
{
bool
isUrl
=
(
toLower
(
s
.
substr
(
i
,
7
))
==
ucstring
(
"http://"
)
||
toLower
(
s
.
substr
(
i
,
8
))
==
ucstring
(
"https://"
));
// match "text http://" and not "texthttp://"
if
(
isUrl
&&
i
>
0
&&
!
markdown
)
{
// '}' is in the list because of color tags, ie "@{FFFF}http://..."
const
ucchar
chars
[]
=
{
' '
,
'"'
,
'\''
,
'('
,
'['
,
'}'
};
isUrl
=
std
::
find
(
std
::
begin
(
chars
),
std
::
end
(
chars
),
s
[
i
-
1
])
!=
std
::
end
(
chars
);
}
return
isUrl
;
}
}
return
false
;
}
// ***************************************************************************
// isUrlTag must match
static
inline
void
getUrlTag
(
const
ucstring
&
s
,
ucstring
::
size_type
&
index
,
ucstring
&
url
,
ucstring
&
title
)
{
bool
isMarkdown
=
false
;
ucstring
::
size_type
textSize
=
s
.
size
();
ucstring
::
size_type
pos
;
// see if we have markdown format
if
(
s
[
index
]
==
'('
)
{
CCDBNodeLeaf
*
node
=
NLGUI
::
CDBManager
::
getInstance
()
->
getDbProp
(
"UI:SAVE:SHOW_CLOCK_12H"
,
false
);
if
(
node
&&
node
->
getValueBool
())
cur_time
=
CInterfaceManager
::
getTimestampHuman
(
"[%I:%M:%S %p] "
);
else
cur_time
=
CInterfaceManager
::
getTimestampHuman
();
index
++
;
pos
=
index
;
while
(
pos
<
textSize
-
9
)
{
if
(
s
[
pos
]
==
')'
&&
s
[
pos
+
1
]
==
'['
)
{
isMarkdown
=
true
;
title
=
s
.
substr
(
index
,
pos
-
index
);
index
=
pos
+
2
;
break
;
}
else
if
(
s
[
pos
]
==
')'
)
{
break
;
}
pos
++
;
}
}
// if text contain any color code, set the text formated and white,
// otherwise, set text normal and apply global color
size_t
codePos
=
msg
.
find
(
ucstring
(
"@{"
));
ucchar
chOpen
=
' '
;
ucchar
chClose
=
' '
;
if
(
isMarkdown
)
{
chOpen
=
'['
;
chClose
=
']'
;
}
else
if
(
index
>
0
)
{
chOpen
=
s
[
index
-
1
];
if
(
chOpen
==
'\''
)
chClose
=
'\''
;
else
if
(
chOpen
==
'"'
)
chClose
=
'"'
;
else
if
(
chOpen
==
'('
)
chClose
=
')'
;
else
if
(
chOpen
==
'['
)
chClose
=
']'
;
else
chClose
=
' '
;
}
if
(
chOpen
==
chClose
)
{
pos
=
s
.
find_first_of
(
chClose
,
index
);
// handle common special case: 'text http://.../, text'
if
(
pos
!=
ucstring
::
npos
&&
index
>
0
)
{
if
(
s
[
index
-
1
]
==
' '
&&
(
s
[
pos
-
1
]
==
','
||
s
[
pos
-
1
]
==
'.'
))
{
pos
--
;
}
}
}
else
{
// scan for nested open/close tags
pos
=
index
;
sint
nested
=
0
;
while
(
pos
<
textSize
)
{
if
(
s
[
pos
]
==
chOpen
)
{
nested
++
;
}
else
if
(
s
[
pos
]
==
chClose
)
{
if
(
nested
==
0
)
{
break
;
}
else
{
nested
--
;
}
}
pos
++
;
}
}
// fallback to full string length as we did match http:// already and url spans to the end probably
if
(
pos
==
ucstring
::
npos
)
{
pos
=
textSize
;
}
url
=
s
.
substr
(
index
,
pos
-
index
);
index
=
pos
;
// skip ']' closing char
if
(
isMarkdown
)
index
++
;
}
//=================================================================================
static
void
prependTimestamp
(
ucstring
&
msg
)
{
ucstring
cur_time
;
CCDBNodeLeaf
*
node
=
NLGUI
::
CDBManager
::
getInstance
()
->
getDbProp
(
"UI:SAVE:SHOW_CLOCK_12H"
,
false
);
if
(
node
&&
node
->
getValueBool
())
cur_time
=
CInterfaceManager
::
getTimestampHuman
(
"[%I:%M:%S %p] "
);
else
cur_time
=
CInterfaceManager
::
getTimestampHuman
();
ucstring
::
size_type
codePos
=
msg
.
find
(
ucstring
(
"@{"
));
if
(
codePos
!=
ucstring
::
npos
)
{
// Prepend the current time (do it after the color if the color at first position.
...
...
@@ -189,13 +321,49 @@ CViewBase *CChatTextManager::createMsgText(const ucstring &cstMsg, NLMISC::CRGBA
{
msg
=
cur_time
+
msg
;
}
}
else
{
msg
=
cur_time
+
msg
;
}
}
//=================================================================================
CViewBase
*
CChatTextManager
::
createMsgText
(
const
ucstring
&
cstMsg
,
NLMISC
::
CRGBA
col
,
bool
justified
/*=false*/
,
bool
plaintext
/*=false*/
)
{
ucstring
msg
=
cstMsg
;
CInterfaceGroup
*
commandGroup
=
parseCommandTag
(
msg
);
if
(
showTimestamps
())
prependTimestamp
(
msg
);
// must wrap all lines to CGroupParagraph because CGroupList will calculate
// width from previous line which ends up as CViewText otherwise
return
createMsgTextComplex
(
msg
,
col
,
justified
,
plaintext
,
commandGroup
);
}
//=================================================================================
CViewBase
*
CChatTextManager
::
createMsgTextSimple
(
const
ucstring
&
msg
,
NLMISC
::
CRGBA
col
,
bool
justified
,
CInterfaceGroup
*
commandGroup
)
{
CViewText
*
vt
=
new
CViewText
(
CViewText
::
TCtorParam
());
// get parameters from config.xml
vt
->
setShadow
(
isTextShadowed
());
vt
->
setShadowOutline
(
false
);
vt
->
setFontSize
(
getTextFontSize
());
vt
->
setMultiLine
(
true
);
vt
->
setTextMode
(
justified
?
CViewText
::
Justified
:
CViewText
::
DontClipWord
);
vt
->
setMultiLineSpace
(
getTextMultiLineSpace
());
vt
->
setModulateGlobalColor
(
false
);
// if text contain any color code, set the text formated and white,
// otherwise, set text normal and apply global color
if
(
msg
.
find
(
ucstring
(
"@{"
))
!=
ucstring
::
npos
)
{
vt
->
setTextFormatTaged
(
msg
);
vt
->
setColor
(
NLMISC
::
CRGBA
::
White
);
}
else
{
msg
=
cur_time
+
msg
;
vt
->
setText
(
msg
);
vt
->
setColor
(
col
);
}
...
...
@@ -210,6 +378,112 @@ CViewBase *CChatTextManager::createMsgText(const ucstring &cstMsg, NLMISC::CRGBA
}
}
//=================================================================================
CViewBase
*
CChatTextManager
::
createMsgTextComplex
(
const
ucstring
&
msg
,
NLMISC
::
CRGBA
col
,
bool
justified
,
bool
plaintext
,
CInterfaceGroup
*
commandGroup
)
{
ucstring
::
size_type
textSize
=
msg
.
size
();
CGroupParagraph
*
para
=
new
CGroupParagraph
(
CViewBase
::
TCtorParam
());
para
->
setId
(
"line"
);
para
->
setSizeRef
(
"w"
);
para
->
setResizeFromChildH
(
true
);
if
(
plaintext
)
{
CViewBase
*
vt
=
createMsgTextSimple
(
msg
,
col
,
justified
,
NULL
);
vt
->
setId
(
"text"
);
para
->
addChild
(
vt
);
return
para
;
}
// quickly check if text has links or not
bool
hasUrl
;
{
ucstring
s
=
toLower
(
msg
);
hasUrl
=
(
s
.
find
(
ucstring
(
"http://"
))
||
s
.
find
(
ucstring
(
"https://"
)));
}
ucstring
::
size_type
pos
=
0
;
for
(
ucstring
::
size_type
i
=
0
;
i
<
textSize
;)
{
if
(
hasUrl
&&
isUrlTag
(
msg
,
i
,
textSize
))
{
if
(
pos
!=
i
)
{
CViewBase
*
vt
=
createMsgTextSimple
(
msg
.
substr
(
pos
,
i
-
pos
),
col
,
justified
,
NULL
);
para
->
addChild
(
vt
);
}
ucstring
url
;
ucstring
title
;
getUrlTag
(
msg
,
i
,
url
,
title
);
if
(
url
.
size
()
>
0
)
{
CViewLink
*
vt
=
new
CViewLink
(
CViewBase
::
TCtorParam
());
vt
->
setId
(
"link"
);
vt
->
setUnderlined
(
true
);
vt
->
setShadow
(
isTextShadowed
());
vt
->
setShadowOutline
(
false
);
vt
->
setFontSize
(
getTextFontSize
());
vt
->
setMultiLine
(
true
);
vt
->
setTextMode
(
justified
?
CViewText
::
Justified
:
CViewText
::
DontClipWord
);
vt
->
setMultiLineSpace
(
getTextMultiLineSpace
());
vt
->
setModulateGlobalColor
(
false
);
//NLMISC::CRGBA color;
//color.blendFromui(col, CRGBA(255, 153, 0, 255), 100);
//vt->setColor(color);
vt
->
setColor
(
col
);
if
(
title
.
size
()
>
0
)
{
vt
->
LinkTitle
=
title
.
toUtf8
();
vt
->
setText
(
title
);
}
else
{
vt
->
LinkTitle
=
url
.
toUtf8
();
vt
->
setText
(
url
);
}
if
(
url
.
find_first_of
(
'\''
)
!=
string
::
npos
)
{
ucstring
clean
;
for
(
string
::
size_type
i
=
0
;
i
<
url
.
size
();
++
i
)
{
if
(
url
[
i
]
==
'\''
)
clean
+=
ucstring
(
"%27"
);
else
clean
+=
url
[
i
];
}
url
=
clean
;
}
vt
->
setActionOnLeftClick
(
"lua"
);
vt
->
setParamsOnLeftClick
(
"game:chatUrl('"
+
url
.
toUtf8
()
+
"')"
);
para
->
addChildLink
(
vt
);
pos
=
i
;
}
}
else
{
++
i
;
}
}
if
(
pos
<
textSize
)
{
CViewBase
*
vt
=
createMsgTextSimple
(
msg
.
substr
(
pos
,
textSize
-
pos
),
col
,
justified
,
NULL
);
vt
->
setId
(
"text"
);
para
->
addChild
(
vt
);
}
return
para
;
}
//=================================================================================
CChatTextManager
&
CChatTextManager
::
getInstance
()
{
...
...
code/ryzom/client/src/interface_v3/chat_text_manager.h
View file @
2e5bcdf2
...
...
@@ -24,6 +24,7 @@
namespace
NLGUI
{
class
CViewBase
;
class
CInterfaceGroup
;
}
class
ucstring
;
...
...
@@ -49,8 +50,9 @@ public:
* \param msg the actual text
* \param col the color of the text
* \param justified Should be true for justified text (stretch spaces of line to fill the full width)
* \param plaintext Text will not be parsed for uri markup links
*/
NLGUI
::
CViewBase
*
createMsgText
(
const
ucstring
&
msg
,
NLMISC
::
CRGBA
col
,
bool
justified
=
false
);
NLGUI
::
CViewBase
*
createMsgText
(
const
ucstring
&
msg
,
NLMISC
::
CRGBA
col
,
bool
justified
=
false
,
bool
plaintext
=
false
);
// Singleton access
static
CChatTextManager
&
getInstance
();
...
...
@@ -73,6 +75,9 @@ private:
~
CChatTextManager
();
bool
showTimestamps
()
const
;
NLGUI
::
CViewBase
*
createMsgTextSimple
(
const
ucstring
&
msg
,
NLMISC
::
CRGBA
col
,
bool
justified
,
NLGUI
::
CInterfaceGroup
*
commandGroup
);
NLGUI
::
CViewBase
*
createMsgTextComplex
(
const
ucstring
&
msg
,
NLMISC
::
CRGBA
col
,
bool
justified
,
bool
plaintext
,
NLGUI
::
CInterfaceGroup
*
commandGroup
);
};
// shortcut to get text manager instance
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment