Merge remote-tracking branch 'ryzomcore/develop' into ryzomclassic-develop

ryzomclassic-develop
kaetemi 5 years ago
commit 33bf80a3c7

@ -63,7 +63,7 @@ public:
keystring, // a string has been sent. The string is a ucstring keystring, // a string has been sent. The string is a ucstring
unknown, // uninitialized event unknown, // uninitialized event
}; };
CEventDescriptorKey() : _KeyEvent(unknown) CEventDescriptorKey() : _KeyEvent(unknown), _CtrlState(false), _ShiftState(false), _AltState(false), _Char(0)
{ {
_EventType = key; _EventType = key;
} }
@ -105,6 +105,31 @@ public:
{ {
return _AltState; return _AltState;
} }
// return true if key was pressed or held down at a time of this event
bool isShiftDown()
{
return (_KeyEvent == CEventDescriptorKey::keydown && (_Key == NLMISC::KeySHIFT || _ShiftState))
|| (_KeyEvent == CEventDescriptorKey::keyup && (_Key != NLMISC::KeySHIFT && _ShiftState))
|| (_KeyEvent == CEventDescriptorKey::keychar && _ShiftState);
}
// return true if key was pressed or held down at a time of this event
bool isCtrlDown()
{
return (_KeyEvent == CEventDescriptorKey::keydown && (_Key == NLMISC::KeyCONTROL || _CtrlState))
|| (_KeyEvent == CEventDescriptorKey::keyup && (_Key != NLMISC::KeyCONTROL && _CtrlState))
|| (_KeyEvent == CEventDescriptorKey::keychar && _CtrlState);
}
// return true if key was pressed or held down at a time of this event
bool isAltDown()
{
return (_KeyEvent == CEventDescriptorKey::keydown && (_Key == NLMISC::KeyMENU || _AltState))
|| (_KeyEvent == CEventDescriptorKey::keyup && (_Key != NLMISC::KeyMENU && _AltState))
|| (_KeyEvent == CEventDescriptorKey::keychar && _AltState);
}
// init from a CEventKey obj // init from a CEventKey obj
void init(const NLMISC::CEventKey &ev); void init(const NLMISC::CEventKey &ev);

@ -360,6 +360,10 @@ namespace NLGUI
// Delete page content and prepare next page // Delete page content and prepare next page
void removeContent (); void removeContent ();
// Counter to number html elements without id attribute
uint32 getNextAutoIdSeq() { return _AutoIdSeq++; }
uint32 _AutoIdSeq;
// Current URL for relative links in page // Current URL for relative links in page
std::string _URL; std::string _URL;
// Current URL // Current URL
@ -679,6 +683,8 @@ namespace NLGUI
std::vector<CEntry> Entries; std::vector<CEntry> Entries;
}; };
std::vector<CForm> _Forms; std::vector<CForm> _Forms;
// if <FORM> element has been closed or not
bool _FormOpen;
// submit buttons added to from // submit buttons added to from
struct SFormSubmitButton struct SFormSubmitButton
@ -949,6 +955,7 @@ namespace NLGUI
//void htmlEM(const CHtmlElement &elm); //void htmlEM(const CHtmlElement &elm);
void htmlFONT(const CHtmlElement &elm); void htmlFONT(const CHtmlElement &elm);
void htmlFORM(const CHtmlElement &elm); void htmlFORM(const CHtmlElement &elm);
void htmlFORMend(const CHtmlElement &elm);
void htmlH(const CHtmlElement &elm); void htmlH(const CHtmlElement &elm);
void htmlHend(const CHtmlElement &elm); void htmlHend(const CHtmlElement &elm);
void htmlHEAD(const CHtmlElement &elm); void htmlHEAD(const CHtmlElement &elm);

@ -267,6 +267,8 @@ namespace NLGUI
bool bReleasable=true bool bReleasable=true
); );
// Create texture from dataURL "data:image/png;base64," string
sint32 createTextureFromDataURL(const std::string &data, bool uploadDXTC=true, bool bReleasable=true);
// change position of a sub-texture (inside its big texture) from the sub-texture filename // change position of a sub-texture (inside its big texture) from the sub-texture filename
void updateTexturePos(const std::string &texturefileName, void updateTexturePos(const std::string &texturefileName,

@ -269,6 +269,14 @@ namespace NLGUI
CViewPointerBase* getPointer(){ return _Pointer; } CViewPointerBase* getPointer(){ return _Pointer; }
void setPointer( CViewPointerBase *pointer ){ _Pointer = pointer; } void setPointer( CViewPointerBase *pointer ){ _Pointer = pointer; }
// If > 0, snap window to others closer than distance
void setWindowSnapDistance(uint32 d) { _WindowSnapDistance = d; }
uint32 getWindowSnapDistance() const { return _WindowSnapDistance; }
// If true, only snap when shift is held down
void setWindowSnapInvert(bool b) { _WindowSnapInvert = b; }
bool getWindowSnapInvert() const { return _WindowSnapInvert; }
/** /**
* get the window under a spot * get the window under a spot
* \param : X coord of the spot * \param : X coord of the spot
@ -310,6 +318,9 @@ namespace NLGUI
void drawOverExtendViewText(); void drawOverExtendViewText();
// Snap to closest visible window border if snapping is enabled
void snapIfClose(CInterfaceGroup *group);
// Internal : adjust a tooltip with respect to its parent. Returns the number of coordinate that were clamped // Internal : adjust a tooltip with respect to its parent. Returns the number of coordinate that were clamped
// against the screen border // against the screen border
uint adjustTooltipPosition( CCtrlBase *newCtrl, CInterfaceGroup *win, THotSpot ttParentRef, uint adjustTooltipPosition( CCtrlBase *newCtrl, CInterfaceGroup *win, THotSpot ttParentRef,
@ -624,6 +635,9 @@ namespace NLGUI
CEventDescriptorKey lastKeyEvent; CEventDescriptorKey lastKeyEvent;
uint32 _WindowSnapDistance;
bool _WindowSnapInvert;
uint32 _ScreenH; uint32 _ScreenH;
uint32 _ScreenW; uint32 _ScreenW;
float _InterfaceScale; float _InterfaceScale;

@ -0,0 +1,154 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef NL_BASE64_H
#define NL_BASE64_h
namespace NLMISC
{
/**
* \brief base64 encode/decode
* \date 2020-01-23 12:39GMT
* \author Meelis Mägi (Nimetu)
*/
struct base64 {
static std::string encode(const std::string &data)
{
/* Conversion table. for base 64 */
static const char tbl[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static const char padChar = '=';
size_t inLength = data.size();
size_t outLength = 4 * ((inLength + 2) / 3);
std::string out;
out.resize(outLength);
size_t iRead=0, oWrite=0;
for (size_t iLoop = 0; iLoop < inLength/3; iLoop++)
{
out[oWrite+0] = tbl[ (data[iRead+0] >> 2) & 0x3F];
out[oWrite+1] = tbl[((data[iRead+0] << 4) & 0x30) + ((data[iRead+1] >> 4) & 0x0F)];
out[oWrite+2] = tbl[((data[iRead+1] << 2) & 0x3C) + ((data[iRead+2] >> 6) & 0x03)];
out[oWrite+3] = tbl[ data[iRead+2] & 0x3F];
iRead += 3;
oWrite += 4;
}
// remaining bytes
switch(inLength % 3)
{
case 2:
out[oWrite+0] = tbl[ (data[iRead+0] >> 2) & 0x3F];
out[oWrite+1] = tbl[((data[iRead+0] << 4) & 0x30) + ((data[iRead+1] >> 4) & 0x0F)];
out[oWrite+2] = tbl[((data[iRead+1] << 2) & 0x3C)];
out[oWrite+3] = padChar;
break;
case 1:
out[oWrite+0] = tbl[ (data[iRead+0] >> 2) & 0x3F];
out[oWrite+1] = tbl[((data[iRead+0] << 4) & 0x30)];
out[oWrite+2] = padChar;
out[oWrite+3] = padChar;
break;
default:
break;
}
return out;
}
static std::string decode(const std::string &in)
{
static sint8 tbl[] = {
// 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 00
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, // 20 + /
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1, // 30 0..9 =
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 40 A..
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, // 50 ..Z
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 60 a..
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, // 70 ..z
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 80
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 90
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // A0
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // B0
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // C0
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // D0
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // E0
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // F0
};
static char padChar = '=';
size_t inLength = in.size();
// add optional padding if its missing from input
size_t outLength = (inLength + inLength % 4) / 4 * 3;
std::string out;
if (inLength > 0)
{
uint8 buf[4];
size_t iBuf = 0;
size_t iRead = 0;
size_t oWrite = 0;
out.resize(outLength);
while(iRead < inLength && in[iRead] != padChar)
{
buf[iBuf] = (uint8)tbl[in[iRead]];
// invalid byte in input
if (buf[iBuf] == 0xFF)
break;
iRead++;
iBuf++;
if (iBuf == 4)
{
out[oWrite+0] = ((buf[0] << 2) & 0xFC) + ((buf[1] >> 4) & 0x0F);
out[oWrite+1] = ((buf[1] << 4) & 0xF0) + ((buf[2] >> 2) & 0x0F);
out[oWrite+2] = ((buf[2] << 6) & 0xC0) + (buf[3] & 0x3F);
oWrite += 3;
iBuf = 0;
}
}
if (iBuf > 0)
{
uint8 tmp[3];
tmp[0] = ((buf[0] << 2) & 0xFC) + ((buf[1] >> 4) & 0x0F);
tmp[1] = ((buf[1] << 4) & 0xF0) + ((buf[2] >> 2) & 0x0F);
tmp[2] = ((buf[2] << 6) & 0xC0) + (buf[3] & 0x3F);
for(uint i = 0; i < iBuf-1; i++, oWrite++)
out[oWrite] = tmp[i];
}
if (out.size() != oWrite)
out.resize(oWrite);
}
return out;
}
};
}//namespace NLMISC
#endif // NL_BASE64_H

@ -307,6 +307,10 @@ template <class T> T trimQuotes (const T &str)
return str.substr(1, size - 2); return str.substr(1, size - 2);
} }
// encode/decode uri component using %AB hex encoding
std::string encodeURIComponent(const std::string &in);
std::string decodeURIComponent(const std::string &in);
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// **** DEPRECATED *****: PLEASE DON'T USE THESE METHODS BUT FUNCTIONS ABOVE toLower() and toUpper() // **** DEPRECATED *****: PLEASE DON'T USE THESE METHODS BUT FUNCTIONS ABOVE toLower() and toUpper()
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////

@ -819,6 +819,8 @@ namespace NLGUI
_Parent->setX(x); _Parent->setX(x);
_Parent->setY(y); _Parent->setY(y);
CWidgetManager::getInstance()->snapIfClose(_Parent);
// if some action handler to call when moving // if some action handler to call when moving
if(gc->getAHOnMovePtr()) if(gc->getAHOnMovePtr())
{ {

@ -718,6 +718,14 @@ namespace NLGUI
std::string finalUrl; std::string finalUrl;
img->setModulateGlobalColor(style.GlobalColor); img->setModulateGlobalColor(style.GlobalColor);
// data:image/png;base64,AA...==
if (startsWith(url, "data:image/"))
{
setImage(img, decodeURIComponent(url), type);
setImageSize(img, style);
return;
}
// load the image from local files/bnp // load the image from local files/bnp
std::string image = CFile::getPath(url) + CFile::getFilenameWithoutExtension(url) + ".tga"; std::string image = CFile::getPath(url) + CFile::getFilenameWithoutExtension(url) + ".tga";
if (lookupLocalFile(finalUrl, image.c_str(), false)) if (lookupLocalFile(finalUrl, image.c_str(), false))
@ -1193,7 +1201,7 @@ namespace NLGUI
case HTML_DT: htmlDTend(elm); break; case HTML_DT: htmlDTend(elm); break;
case HTML_EM: renderPseudoElement(":after", elm);break; case HTML_EM: renderPseudoElement(":after", elm);break;
case HTML_FONT: break; case HTML_FONT: break;
case HTML_FORM: renderPseudoElement(":after", elm);break; case HTML_FORM: htmlFORMend(elm); break;
case HTML_H1://no-break case HTML_H1://no-break
case HTML_H2://no-break case HTML_H2://no-break
case HTML_H3://no-break case HTML_H3://no-break
@ -1447,6 +1455,8 @@ namespace NLGUI
_LastRefreshTime = 0.0; _LastRefreshTime = 0.0;
_RenderNextTime = false; _RenderNextTime = false;
_WaitingForStylesheet = false; _WaitingForStylesheet = false;
_AutoIdSeq = 0;
_FormOpen = false;
// Register // Register
CWidgetManager::getInstance()->registerClockMsgTarget(this); CWidgetManager::getInstance()->registerClockMsgTarget(this);
@ -2535,6 +2545,7 @@ namespace NLGUI
{ {
// Add a new paragraph // Add a new paragraph
CGroupParagraph *newParagraph = new CGroupParagraph(CViewBase::TCtorParam()); CGroupParagraph *newParagraph = new CGroupParagraph(CViewBase::TCtorParam());
newParagraph->setId(getCurrentGroup()->getId() + ":PARAGRAPH" + toString(getNextAutoIdSeq()));
newParagraph->setResizeFromChildH(true); newParagraph->setResizeFromChildH(true);
newParagraph->setMarginLeft(getIndent()); newParagraph->setMarginLeft(getIndent());
@ -3137,11 +3148,17 @@ namespace NLGUI
ctrlButton->setId(name); ctrlButton->setId(name);
} }
std::string normal;
if (startsWith(normalBitmap, "data:image/"))
{
normal = decodeURIComponent(normalBitmap);
}
else
{
// Load only tga files.. (conversion in dds filename is done in the lookup procedure) // Load only tga files.. (conversion in dds filename is done in the lookup procedure)
string normal = normalBitmap.empty()?"":CFile::getPath(normalBitmap) + CFile::getFilenameWithoutExtension(normalBitmap) + ".tga"; normal = normalBitmap.empty()?"":CFile::getPath(normalBitmap) + CFile::getFilenameWithoutExtension(normalBitmap) + ".tga";
// if the image doesn't exist on local, we check in the cache // if the image doesn't exist on local, we check in the cache
// if(!CFile::fileExists(normal))
if(!CPath::exists(normal)) if(!CPath::exists(normal))
{ {
// search in the compressed texture // search in the compressed texture
@ -3153,10 +3170,17 @@ namespace NLGUI
addImageDownload(normalBitmap, ctrlButton, style); addImageDownload(normalBitmap, ctrlButton, style);
} }
} }
}
string pushed = pushedBitmap.empty()?"":CFile::getPath(pushedBitmap) + CFile::getFilenameWithoutExtension(pushedBitmap) + ".tga"; std::string pushed;
if (startsWith(pushedBitmap, "data:image/"))
{
pushed = decodeURIComponent(pushedBitmap);
}
else
{
pushed = pushedBitmap.empty()?"":CFile::getPath(pushedBitmap) + CFile::getFilenameWithoutExtension(pushedBitmap) + ".tga";
// if the image doesn't exist on local, we check in the cache, don't download it because the "normal" will already setuped it // if the image doesn't exist on local, we check in the cache, don't download it because the "normal" will already setuped it
// if(!CFile::fileExists(pushed))
if(!CPath::exists(pushed)) if(!CPath::exists(pushed))
{ {
// search in the compressed texture // search in the compressed texture
@ -3167,8 +3191,16 @@ namespace NLGUI
pushed = localImageName(pushedBitmap); pushed = localImageName(pushedBitmap);
} }
} }
}
string over = overBitmap.empty()?"":CFile::getPath(overBitmap) + CFile::getFilenameWithoutExtension(overBitmap) + ".tga"; std::string over;
if (startsWith(overBitmap, "data:image/"))
{
over = decodeURIComponent(overBitmap);
}
else
{
over = overBitmap.empty()?"":CFile::getPath(overBitmap) + CFile::getFilenameWithoutExtension(overBitmap) + ".tga";
// schedule mouseover bitmap for download if its different from normal // schedule mouseover bitmap for download if its different from normal
if (!over.empty() && !CPath::exists(over)) if (!over.empty() && !CPath::exists(over))
{ {
@ -3178,6 +3210,7 @@ namespace NLGUI
addImageDownload(overBitmap, ctrlButton, style, OverImage); addImageDownload(overBitmap, ctrlButton, style, OverImage);
} }
} }
}
ctrlButton->setType (type); ctrlButton->setType (type);
if (!normal.empty()) if (!normal.empty())
@ -3242,6 +3275,7 @@ namespace NLGUI
_Cells.clear(); _Cells.clear();
_TR.clear(); _TR.clear();
_Forms.clear(); _Forms.clear();
_FormOpen = false;
_FormSubmit.clear(); _FormSubmit.clear();
_Groups.clear(); _Groups.clear();
_Divs.clear(); _Divs.clear();
@ -3255,6 +3289,7 @@ namespace NLGUI
_ReadingHeadTag = false; _ReadingHeadTag = false;
_IgnoreHeadTag = false; _IgnoreHeadTag = false;
_IgnoreBaseUrlTag = false; _IgnoreBaseUrlTag = false;
_AutoIdSeq = 0;
paragraphChange (); paragraphChange ();
@ -4331,6 +4366,7 @@ namespace NLGUI
if (!_GroupListAdaptor) if (!_GroupListAdaptor)
{ {
_GroupListAdaptor = new CGroupListAdaptor(CViewBase::TCtorParam()); // deleted by the list _GroupListAdaptor = new CGroupListAdaptor(CViewBase::TCtorParam()); // deleted by the list
_GroupListAdaptor->setId(getList()->getId() + ":GLA");
_GroupListAdaptor->setResizeFromChildH(true); _GroupListAdaptor->setResizeFromChildH(true);
getList()->addChild (_GroupListAdaptor, true); getList()->addChild (_GroupListAdaptor, true);
} }
@ -5545,6 +5581,11 @@ namespace NLGUI
std::string tooltip = elm.getAttribute("tooltip"); std::string tooltip = elm.getAttribute("tooltip");
bool disabled = elm.hasAttribute("disabled"); bool disabled = elm.hasAttribute("disabled");
if (formId.empty() && _FormOpen)
{
formId = _Forms.back().id;
}
if (!formAction.empty()) if (!formAction.empty())
{ {
formAction = getAbsoluteUrl(formAction); formAction = getAbsoluteUrl(formAction);
@ -5647,6 +5688,8 @@ namespace NLGUI
{ {
string style = elm.getAttribute("style"); string style = elm.getAttribute("style");
string id = elm.getAttribute("id"); string id = elm.getAttribute("id");
if (id.empty())
id = "DIV" + toString(getNextAutoIdSeq());
typedef pair<string, string> TTmplParam; typedef pair<string, string> TTmplParam;
vector<TTmplParam> tmplParams; vector<TTmplParam> tmplParams;
@ -5679,10 +5722,10 @@ namespace NLGUI
parentId = _Paragraph->getId(); parentId = _Paragraph->getId();
} }
CInterfaceGroup *inst = CWidgetManager::getInstance()->getParser()->createGroupInstance(templateName, this->_Id+":"+id, tmplParams); CInterfaceGroup *inst = CWidgetManager::getInstance()->getParser()->createGroupInstance(templateName, parentId, tmplParams);
if (inst) if (inst)
{ {
inst->setId(this->_Id+":"+id); inst->setId(parentId+":"+id);
inst->updateCoords(); inst->updateCoords();
if (haveParentDiv) if (haveParentDiv)
{ {
@ -5815,6 +5858,8 @@ namespace NLGUI
// *************************************************************************** // ***************************************************************************
void CGroupHTML::htmlFORM(const CHtmlElement &elm) void CGroupHTML::htmlFORM(const CHtmlElement &elm)
{ {
_FormOpen = true;
// Build the form // Build the form
CGroupHTML::CForm form; CGroupHTML::CForm form;
// id check is case sensitive and auto id's are uppercase // id check is case sensitive and auto id's are uppercase
@ -5839,6 +5884,12 @@ namespace NLGUI
renderPseudoElement(":before", elm); renderPseudoElement(":before", elm);
} }
void CGroupHTML::htmlFORMend(const CHtmlElement &elm)
{
_FormOpen = false;
renderPseudoElement(":after", elm);
}
// *************************************************************************** // ***************************************************************************
void CGroupHTML::htmlH(const CHtmlElement &elm) void CGroupHTML::htmlH(const CHtmlElement &elm)
{ {
@ -6374,6 +6425,12 @@ namespace NLGUI
if (_Forms.empty() || _Forms.back().Entries.empty()) if (_Forms.empty() || _Forms.back().Entries.empty())
return; return;
// use option text as value
if (!elm.hasAttribute("value"))
{
_Forms.back().Entries.back().SelectValues.back() = _SelectOptionStr.toUtf8();
}
// insert the parsed text into the select control // insert the parsed text into the select control
CDBGroupComboBox *cb = _Forms.back().Entries.back().ComboBox; CDBGroupComboBox *cb = _Forms.back().Entries.back().ComboBox;
if (cb) if (cb)
@ -6611,6 +6668,10 @@ namespace NLGUI
CGroupTable *table = new CGroupTable(TCtorParam()); CGroupTable *table = new CGroupTable(TCtorParam());
table->BgColor = _CellParams.back().BgColor; table->BgColor = _CellParams.back().BgColor;
if (elm.hasNonEmptyAttribute("id"))
table->setId(getCurrentGroup()->getId() + ":" + elm.getAttribute("id"));
else
table->setId(getCurrentGroup()->getId() + ":TABLE" + toString(getNextAutoIdSeq()));
// TODO: border-spacing: 2em; // TODO: border-spacing: 2em;
{ {
@ -6771,6 +6832,12 @@ namespace NLGUI
} }
_Cells.back() = new CGroupCell(CViewBase::TCtorParam()); _Cells.back() = new CGroupCell(CViewBase::TCtorParam());
if (elm.hasNonEmptyAttribute("id"))
_Cells.back()->setId(table->getId() + ":" + elm.getAttribute("id"));
else
_Cells.back()->setId(table->getId() + ":TD" + toString(getNextAutoIdSeq()));
// inner cell content
_Cells.back()->Group->setId(_Cells.back()->getId() + ":CELL");
if (_Style.checkStyle("background-repeat", "repeat")) if (_Style.checkStyle("background-repeat", "repeat"))
_Cells.back()->setTextureTile(true); _Cells.back()->setTextureTile(true);

@ -610,16 +610,12 @@ namespace NLGUI
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void CGroupCell::setTextureTile(bool tiled) void CGroupCell::setTextureTile(bool tiled)
{ {
if (tiled)
nlinfo("Set texture is Tiled");
_TextureTiled = tiled; _TextureTiled = tiled;
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void CGroupCell::setTextureScale(bool scaled) void CGroupCell::setTextureScale(bool scaled)
{ {
if (scaled)
nlinfo("Set texture is Scaled : %s");
_TextureScaled = scaled; _TextureScaled = scaled;
} }

@ -481,7 +481,7 @@ namespace NLGUI
} }
} }
else else
_TextureId.setTexture (toLower(TxName).c_str (), _TxtOffsetX, _TxtOffsetY, _TxtWidth, _TxtHeight, false); _TextureId.setTexture (TxName.c_str (), _TxtOffsetX, _TxtOffsetY, _TxtWidth, _TxtHeight, false);
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

@ -24,6 +24,8 @@
#include "nel/misc/file.h" #include "nel/misc/file.h"
#include "nel/misc/uv.h" #include "nel/misc/uv.h"
#include "nel/misc/hierarchical_timer.h" #include "nel/misc/hierarchical_timer.h"
#include "nel/misc/base64.h"
#include "nel/misc/md5.h"
using namespace NLMISC; using namespace NLMISC;
using namespace std; using namespace std;
@ -998,6 +1000,10 @@ namespace NLGUI
) )
{ {
if (sGlobalTextureName.empty()) return -1; if (sGlobalTextureName.empty()) return -1;
if (startsWith(sGlobalTextureName, "data:image/"))
return createTextureFromDataURL(sGlobalTextureName, uploadDXTC, bReleasable);
// Look if already existing // Look if already existing
string sLwrGTName = toLower(sGlobalTextureName); string sLwrGTName = toLower(sGlobalTextureName);
TGlobalTextureList::iterator ite = _GlobalTextures.begin(); TGlobalTextureList::iterator ite = _GlobalTextures.begin();
@ -1062,6 +1068,93 @@ namespace NLGUI
return TextID; return TextID;
} }
sint32 CViewRenderer::createTextureFromDataURL(const std::string &data, bool uploadDXTC, bool bReleasable)
{
if (!startsWith(data, "data:image/"))
return -1;
size_t pos = data.find(";base64,");
if (pos == std::string::npos)
{
nlwarning("Failed to parse dataURL (not base64?) '%s'", data.c_str());
return -1;
}
std::string md5hash = getMD5((uint8 *)data.c_str(), (uint32)data.size()).toString();
TGlobalTextureList::iterator ite = _GlobalTextures.begin();
while (ite != _GlobalTextures.end())
{
if (md5hash == ite->Name)
break;
ite++;
}
// If global texture not exists create it
if (ite == _GlobalTextures.end())
{
std::string decoded = base64::decode(data.substr(pos + 8));
if (decoded.empty())
{
nlwarning("base64 decode failed '%s'", data.substr(pos + 8).c_str());
return -1;
}
//
CMemStream buf;
if (buf.isReading()) buf.invert();
buf.serialBuffer((uint8 *)(decoded.data()), decoded.size());
buf.invert();
CBitmap btm;
btm.load(buf);
SGlobalTexture gtTmp;
gtTmp.FromGlobaleTexture = false;
gtTmp.Width = gtTmp.DefaultWidth = btm.getWidth();;
gtTmp.Height = gtTmp.DefaultHeight = btm.getHeight();
if (gtTmp.Width == 0 || gtTmp.Height == 0)
{
nlwarning("Failed to load the texture '%s', please check image format", data.c_str());
return -1;
}
UTextureMem *texture = driver->createTextureMem(btm.getWidth(), btm.getHeight(), CBitmap::RGBA);
if (!texture)
{
nlwarning("Failed to create mem texture (%d,%d)", btm.getWidth(), btm.getHeight());
return -1;
}
memcpy(texture->getPointer(), btm.getPixels().getPtr(), btm.getSize() * 4);
gtTmp.Texture = texture;
gtTmp.Name = md5hash;
gtTmp.Texture->setFilterMode(UTexture::Nearest, UTexture::NearestMipMapOff);
gtTmp.Texture->setReleasable(bReleasable);
if(uploadDXTC)
gtTmp.Texture->setUploadFormat(UTexture::DXTC5);
_GlobalTextures.push_back(gtTmp);
ite = _GlobalTextures.end();
ite--;
}
// Add a texture with reference to the i th global texture
SImage iTmp;
// Set default parameters
iTmp.Name = data;
iTmp.GlobalTexturePtr = &(*ite);
iTmp.UVMin = CUV(0.f , 0.f);
iTmp.UVMax = CUV(1.f , 1.f);
sint32 TextID = addSImage(iTmp);
return TextID;
}
void CViewRenderer::updateTexturePos(const std::string &texturefileName, sint32 offsetX /*=0*/, sint32 offsetY /*=0*/, sint32 width /*=-1*/, sint32 height /*=-1*/) void CViewRenderer::updateTexturePos(const std::string &texturefileName, sint32 offsetX /*=0*/, sint32 offsetY /*=0*/, sint32 width /*=-1*/, sint32 height /*=-1*/)
{ {
sint32 id = getTextureIdFromName (texturefileName); sint32 id = getTextureIdFromName (texturefileName);
@ -1159,6 +1252,11 @@ namespace NLGUI
{ {
driver->deleteTextureFile (tf); driver->deleteTextureFile (tf);
} }
else
{
UTextureMem *tf = dynamic_cast<NL3D::UTextureMem *>(iteGT->Texture);
if (tf) driver->deleteTextureMem(tf);
}
_GlobalTextures.erase (iteGT); _GlobalTextures.erase (iteGT);
return; return;
} }

@ -1205,6 +1205,10 @@ namespace NLGUI
CViewText *vtDst = dynamic_cast<CViewText*>(groupOver->getView("text")); CViewText *vtDst = dynamic_cast<CViewText*>(groupOver->getView("text"));
if (vtDst != NULL) if (vtDst != NULL)
{ {
groupOver->setParentPos(vtSrc);
sint32 backupX = groupOver->getX();
// Copy all aspects to the view // Copy all aspects to the view
vtDst->setText (vtSrc->getText()); vtDst->setText (vtSrc->getText());
vtDst->setFontSize (vtSrc->getFontSize()); vtDst->setFontSize (vtSrc->getFontSize());
@ -1227,42 +1231,36 @@ namespace NLGUI
pOutline->setModulateGlobalColor(vtSrc->getModulateGlobalColor()); pOutline->setModulateGlobalColor(vtSrc->getModulateGlobalColor());
} }
// the group is the position of the overed text, but apply the delta of borders (vtDst X/Y)
sint32 x = vtSrc->getXReal() - vtDst->getX();
sint32 y = vtSrc->getYReal() - vtDst->getY();
// update one time only to get correct W/H // update one time only to get correct W/H
groupOver->updateCoords (); groupOver->updateCoords ();
if(!vtSrc->isClampRight()) // align and clamp to screen coords
sint32 x = -backupX;
if (vtSrc->isClampRight())
{ {
// clamped from the left part x += std::max(0, (groupOver->getXReal() + groupOver->getWReal()) - (groupOver->getParent()->getXReal() + groupOver->getParent()->getWReal()));
x += vtSrc->getWReal() - vtDst->getWReal();
} }
else
{
x += vtDst->getWReal() - vtSrc->getWReal();
if ( x > (groupOver->getXReal() - groupOver->getParent()->getXReal()) )
{
x -= x - (groupOver->getXReal() - groupOver->getParent()->getXReal());
}
}
if (x != 0) groupOver->setX(-x);
// clamp to screen coords, and set // TODO: there should be no overflow on y, unless barely visible and next to screen border
if ((x+groupOver->getW()) > groupOver->getParent()->getWReal())
x = groupOver->getParent()->getWReal() - groupOver->getW();
if (x < 0)
x = 0;
if ((y+groupOver->getH()) > groupOver->getParent()->getHReal())
y = groupOver->getParent()->getHReal() - groupOver->getH();
if (y < 0)
y = 0;
// set pos
groupOver->setX (x);
groupOver->setY (y);
// update coords 3 times is required
groupOver->updateCoords ();
groupOver->updateCoords ();
groupOver->updateCoords(); groupOver->updateCoords();
// draw // draw
groupOver->draw (); groupOver->draw ();
// flush layers // flush layers
CViewRenderer::getInstance()->flush(); CViewRenderer::getInstance()->flush();
// restore backup values
if (x != 0) groupOver->setX(backupX);
} }
} }
@ -1271,7 +1269,125 @@ namespace NLGUI
} }
} }
// ----------------------------------------------------------------------------
void CWidgetManager::snapIfClose(CInterfaceGroup *group)
{
if (!group || _WindowSnapDistance == 0 || _WindowSnapInvert != lastKeyEvent.isShiftDown())
return;
uint hsnap = _WindowSnapDistance;
uint vsnap = _WindowSnapDistance;
sint32 newX = group->getX();
sint32 newY = group->getY();
// new coords for window without snap
// used to calculate distance from target
sint gLeft = newX;
sint gRight = newX + group->getWReal();
sint gTop = newY;
sint gBottom = newY - group->getHReal();
// current window coords as if already snaped
// used to calculate target for snap
sint gLeftR = group->getXReal();
sint gRightR = gLeftR + group->getWReal();
sint gBottomR = group->getYReal();
sint gTopR = gBottomR + group->getHReal();
for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
{
CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
if (!rMG.Group->getActive()) continue;
for (uint8 nPriority = WIN_PRIORITY_MAX; nPriority > 0 ; nPriority--)
{
const std::list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority-1];
std::list<CInterfaceGroup*>::const_reverse_iterator itw;
for (itw = rList.rbegin(); itw != rList.rend(); itw++)
{
CInterfaceGroup *pIG = *itw;
// do not snap to self, inactive, or not using mouse interaction
if (group == pIG || !(pIG->getActive() && pIG->getUseCursor()))
continue;
// target
sint wLeft = pIG->getXReal();
sint wRight = pIG->getXReal() + pIG->getWReal();
sint wTop = pIG->getYReal() + pIG->getHReal();
sint wBottom = pIG->getYReal();
sint delta;
if (gTopR >= wBottom && gBottomR <= wTop)
{
delta = abs(gRight - wLeft);
if (delta <= hsnap)
{
hsnap = delta;
newX = wLeft - group->getWReal();
}
delta = abs(gLeft - wRight);
if (delta <= hsnap)
{
hsnap = delta;
newX = wRight;
}
delta = abs(gLeft - wLeft);
if (delta <= hsnap)
{
hsnap = delta;
newX = wLeft;
}
delta = abs(gRight - wRight);
if (delta <= hsnap)
{
hsnap = delta;
newX = wRight - group->getWReal();
}
}
if (gLeftR <= wRight && gRightR >= wLeft)
{
delta = abs(gTop - wBottom);
if (delta <= vsnap)
{
vsnap = delta;
newY = wBottom;
}
delta = abs(gBottom - wTop);
if (delta <= vsnap)
{
vsnap = delta;
newY = wTop + group->getHReal();
}
delta = abs(gTop - wTop);
if (delta <= vsnap)
{
vsnap = delta;
newY = wTop;
}
delta = abs(gBottom - wBottom);
if (delta <= vsnap)
{
vsnap = delta;
newY = wBottom + group->getHReal();
}
}
}//windows
}//priority
}//master group
group->setX(newX);
group->setY(newY);
}
// ----------------------------------------------------------------------------
uint CWidgetManager::adjustTooltipPosition( CCtrlBase *newCtrl, CInterfaceGroup *win, THotSpot ttParentRef, uint CWidgetManager::adjustTooltipPosition( CCtrlBase *newCtrl, CInterfaceGroup *win, THotSpot ttParentRef,
THotSpot ttPosRef, sint32 xParent, sint32 yParent, THotSpot ttPosRef, sint32 xParent, sint32 yParent,
sint32 wParent, sint32 hParent ) sint32 wParent, sint32 hParent )
@ -3788,6 +3904,9 @@ namespace NLGUI
setScreenWH(0, 0); setScreenWH(0, 0);
_InterfaceScale = 1.0f; _InterfaceScale = 1.0f;
_WindowSnapDistance = 10;
_WindowSnapInvert = false;
_GroupSelection = false; _GroupSelection = false;
multiSelection = false; multiSelection = false;
_WidgetCount = 0; _WidgetCount = 0;

@ -784,6 +784,94 @@ bool fromHexa(const char hexa, uint8 &b)
return false; return false;
} }
static std::vector<char> makeCharLookupTable(const std::string &chars)
{
std::vector<char> out(256, -1);
for(uint i = 0; i< chars.size(); i++)
out[chars[i]] = i;
return out;
}
std::string encodeURIComponent(const std::string &in)
{
static const char hexLookup[] = "0123456789ABCDEF";
static const std::vector<char> notEscaped(makeCharLookupTable(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
"-_.!~*'()"
));
if (in.empty())
return std::string();
std::string out;
size_t inSize = in.size();
size_t outSize = in.size();
// resize to worst case for smaller strings,
// give some replacements for free for larger strings
if (in.size() < 100)
out.reserve(in.size() * 3);
else
out.reserve(in.size() + 200);
for(size_t i = 0; i < inSize; i++)
{
char ch = in[i];
if (notEscaped[(uint8)ch] == -1)
{
out += '%';
out += hexLookup[(ch>>4)& 0x0F];
out += hexLookup[ch & 0x0F];
outSize += 2;
}
else
{
out += ch;
}
}
// resize back to correct size
out.resize(outSize);
return out;
}
std::string decodeURIComponent(const std::string &in)
{
if (in.find("%") == std::string::npos)
return in;
std::string out;
out.resize(in.size());
size_t outIndex = 0, inSize = in.size();
for(size_t i = 0; i < inSize; i++, outIndex++)
{
if (in[i] == '%' && (i+2 < inSize))
{
uint8 a;
uint8 b;
if (fromHexa(in[i+1], a) && fromHexa(in[i+2], b))
{
out[outIndex] = (a << 4) | b;
i += 2;
} else {
// not hex chars
out[outIndex] = in[i];
}
}
else
{
out[outIndex] = in[i];
}
}
out.resize(outIndex);
return out;
}
std::string formatThousands(const std::string& s) std::string formatThousands(const std::string& s)
{ {
sint i, k; sint i, k;

@ -31,6 +31,7 @@
#include "ut_misc_variable.h" #include "ut_misc_variable.h"
#include "ut_misc_types.h" #include "ut_misc_types.h"
#include "ut_misc_string_common.h" #include "ut_misc_string_common.h"
#include "ut_misc_base64.h"
// Add a line here when adding a new test CLASS // Add a line here when adding a new test CLASS
struct CUTMisc : public Test::Suite struct CUTMisc : public Test::Suite
@ -51,6 +52,7 @@ struct CUTMisc : public Test::Suite
add(std::auto_ptr<Test::Suite>(new CUTMiscVariable)); add(std::auto_ptr<Test::Suite>(new CUTMiscVariable));
add(std::auto_ptr<Test::Suite>(new CUTMiscTypes)); add(std::auto_ptr<Test::Suite>(new CUTMiscTypes));
add(std::auto_ptr<Test::Suite>(new CUTMiscStringCommon)); add(std::auto_ptr<Test::Suite>(new CUTMiscStringCommon));
add(std::auto_ptr<Test::Suite>(new CUTMiscBase64));
// Add a line here when adding a new test CLASS // Add a line here when adding a new test CLASS
} }
}; };

@ -0,0 +1,82 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef UT_MISC_BASE64
#define UT_MISC_BASE64
#include <nel/misc/base64.h>
struct CUTMiscBase64 : public Test::Suite
{
CUTMiscBase64()
{
TEST_ADD(CUTMiscBase64::testEncode);
TEST_ADD(CUTMiscBase64::testDecode);
TEST_ADD(CUTMiscBase64::testDecodeNoPadding);
TEST_ADD(CUTMiscBase64::testDecodeInvalid);
}
void testEncode()
{
TEST_ASSERT("" == NLMISC::base64::encode(""));
TEST_ASSERT("AA==" == NLMISC::base64::encode(std::string(1, '\0')));
TEST_ASSERT("YQ==" == NLMISC::base64::encode("a"));
TEST_ASSERT("YWI=" == NLMISC::base64::encode("ab"));
TEST_ASSERT("YWJj" == NLMISC::base64::encode("abc"));
std::string expect = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NTY3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==";
std::string encoded = NLMISC::base64::encode("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#0^&*();:<>,. []{}");
TEST_ASSERT(expect == encoded);
}
void testDecode()
{
TEST_ASSERT("" == NLMISC::base64::decode(""));
TEST_ASSERT("" == NLMISC::base64::decode("="));
TEST_ASSERT("" == NLMISC::base64::decode("=="));
TEST_ASSERT("" == NLMISC::base64::decode("==="));
TEST_ASSERT("" == NLMISC::base64::decode("===="));
TEST_ASSERT(std::string(1, '\0') == NLMISC::base64::decode("AA=="));
TEST_ASSERT("a" == NLMISC::base64::decode("YQ=="));
TEST_ASSERT("ab" == NLMISC::base64::decode("YWI="));
TEST_ASSERT("abc" == NLMISC::base64::decode("YWJj"));
std::string expect = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#0^&*();:<>,. []{}";
std::string decoded = NLMISC::base64::decode("YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NTY3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==");
TEST_ASSERT(expect == decoded);
}
void testDecodeNoPadding()
{
TEST_ASSERT(std::string(1, '\0') == NLMISC::base64::decode("AA"));
TEST_ASSERT("a" == NLMISC::base64::decode("YQ"));
TEST_ASSERT("ab" == NLMISC::base64::decode("YWI"));
std::string expect = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#0^&*();:<>,. []{}";
std::string decoded = NLMISC::base64::decode("YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NTY3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ");
TEST_ASSERT(expect == decoded);
}
void testDecodeInvalid()
{
TEST_ASSERT("" == NLMISC::base64::decode("A"));
TEST_ASSERT("" == NLMISC::base64::decode("A==="));
}
};
#endif

@ -26,6 +26,8 @@ struct CUTMiscCommon : public Test::Suite
{ {
TEST_ADD(CUTMiscCommon::bytesToHumanReadableUnits); TEST_ADD(CUTMiscCommon::bytesToHumanReadableUnits);
TEST_ADD(CUTMiscCommon::humanReadableToBytes); TEST_ADD(CUTMiscCommon::humanReadableToBytes);
TEST_ADD(CUTMiscCommon::encodeURIComponent);
TEST_ADD(CUTMiscCommon::decodeURIComponent);
// Add a line here when adding a new test METHOD // Add a line here when adding a new test METHOD
} }
@ -166,6 +168,27 @@ struct CUTMiscCommon : public Test::Suite
bytes = NLMISC::humanReadableToBytes("-1 B"); bytes = NLMISC::humanReadableToBytes("-1 B");
TEST_ASSERT(bytes == 0); TEST_ASSERT(bytes == 0);
} }
void encodeURIComponent()
{
TEST_ASSERT("%00" == NLMISC::encodeURIComponent(std::string("\x00", 1)));
TEST_ASSERT("%0A" == NLMISC::encodeURIComponent(std::string("\x0A", 1)));
TEST_ASSERT("%A0" == NLMISC::encodeURIComponent(std::string("\xA0", 1)));
TEST_ASSERT("a%20b" == NLMISC::encodeURIComponent("a b"));
TEST_ASSERT("a%2Bb" == NLMISC::encodeURIComponent("a+b"));
}
void decodeURIComponent()
{
TEST_ASSERT(std::string("\x00", 1) == NLMISC::decodeURIComponent(std::string("\x00", 1)));
TEST_ASSERT(std::string("\x0A", 1) == NLMISC::decodeURIComponent(std::string("\x0A", 1)));
TEST_ASSERT(std::string("\xA0", 1) == NLMISC::decodeURIComponent(std::string("\xA0", 1)));
TEST_ASSERT("a b" == NLMISC::decodeURIComponent("a%20b"));
TEST_ASSERT("a+b" == NLMISC::decodeURIComponent("a%2Bb"));
TEST_ASSERT("a%A" == NLMISC::decodeURIComponent("a%A"));
TEST_ASSERT("a%AX" == NLMISC::decodeURIComponent("a%AX"));
}
}; };
#endif #endif

@ -338,6 +338,9 @@ BilinearUI = 1;
MaxMapScale = 2.0; MaxMapScale = 2.0;
R2EDMaxMapScale = 8.0; R2EDMaxMapScale = 8.0;
WindowSnapInvert = 0;
WindowSnapDistance = 10;
////////////////// //////////////////
// SOUND CONFIG // // SOUND CONFIG //
////////////////// //////////////////

@ -316,6 +316,9 @@ CClientConfig::CClientConfig()
InterfaceScale_step = 0.05; InterfaceScale_step = 0.05;
BilinearUI = true; BilinearUI = true;
WindowSnapInvert = false;
WindowSnapDistance = 10;
VREnable = false; VREnable = false;
VRDisplayDevice = "Auto"; VRDisplayDevice = "Auto";
VRDisplayDeviceId = ""; VRDisplayDeviceId = "";
@ -859,6 +862,8 @@ void CClientConfig::setValues()
READ_FLOAT_FV(InterfaceScale_step); READ_FLOAT_FV(InterfaceScale_step);
clamp(ClientCfg.InterfaceScale, ClientCfg.InterfaceScale_min, ClientCfg.InterfaceScale_max); clamp(ClientCfg.InterfaceScale, ClientCfg.InterfaceScale_min, ClientCfg.InterfaceScale_max);
READ_BOOL_FV(BilinearUI); READ_BOOL_FV(BilinearUI);
READ_BOOL_FV(WindowSnapInvert);
READ_INT_FV(WindowSnapDistance);
// 3D Driver // 3D Driver
varPtr = ClientCfg.ConfigFile.getVarPtr ("Driver3D"); varPtr = ClientCfg.ConfigFile.getVarPtr ("Driver3D");
if (varPtr) if (varPtr)

@ -157,6 +157,10 @@ struct CClientConfig
float InterfaceScale_step; float InterfaceScale_step;
bool BilinearUI; bool BilinearUI;
// Window snap
bool WindowSnapInvert;
uint32 WindowSnapDistance;
// VR // VR
bool VREnable; bool VREnable;
std::string VRDisplayDevice; std::string VRDisplayDevice;

@ -1353,6 +1353,9 @@ void prelogInit()
CViewRenderer::getInstance()->setInterfaceScale(1.0f, 1024, 768); CViewRenderer::getInstance()->setInterfaceScale(1.0f, 1024, 768);
CViewRenderer::getInstance()->setBilinearFiltering(ClientCfg.BilinearUI); CViewRenderer::getInstance()->setBilinearFiltering(ClientCfg.BilinearUI);
CWidgetManager::getInstance()->setWindowSnapInvert(ClientCfg.WindowSnapInvert);
CWidgetManager::getInstance()->setWindowSnapDistance(ClientCfg.WindowSnapDistance);
// Yoyo: initialize NOW the InputHandler for Event filtering. // Yoyo: initialize NOW the InputHandler for Event filtering.
CInputHandlerManager *InputHandlerManager = CInputHandlerManager::getInstance(); CInputHandlerManager *InputHandlerManager = CInputHandlerManager::getInstance();
InputHandlerManager->addToServer (&Driver->EventServer); InputHandlerManager->addToServer (&Driver->EventServer);

@ -1120,8 +1120,8 @@ class CHandlerHTMLSubmitForm : public IActionHandler
return; return;
} }
sint32 x = pCaller->getEventX(); sint32 x = pCaller ? pCaller->getEventX() : 0;
sint32 y = pCaller->getEventY(); sint32 y = pCaller ? pCaller->getEventY() : 0;
CInterfaceElement *element = CWidgetManager::getInstance()->getElementFromId(container); CInterfaceElement *element = CWidgetManager::getInstance()->getElementFromId(container);
{ {
@ -1131,6 +1131,10 @@ class CHandlerHTMLSubmitForm : public IActionHandler
{ {
groupHtml->submitForm(button, x, y); groupHtml->submitForm(button, x, y);
} }
else
{
nlwarning("CGroupHTML with id '%s' not found.", container.c_str());
}
} }
} }
}; };

@ -323,6 +323,19 @@ namespace EFFECT_FAMILIES
{ "thorn_wall_aura.sbrick", PowerThornWall }, { "thorn_wall_aura.sbrick", PowerThornWall },
{ "water_wall_aura.sbrick", PowerWaterWall }, { "water_wall_aura.sbrick", PowerWaterWall },
{ "lightning_wall_aura.sbrick", PowerLightningWall }, { "lightning_wall_aura.sbrick", PowerLightningWall },
{ "life_aura.sbrick", PowerRootLifeAura },
{ "stamina_aura.sbrick", PowerRootStaminaAura },
{ "sap_aura.sbrick", PowerRootSapAura },
{ "umbrella_aura.sbrick", PowerRootUmbrella },
{ "melee_protection_aura.sbrick", PowerRootProtection },
{ "anti_magic_shield_aura.sbrick", PowerRootAntiMagicShield },
{ "war_cry_aura.sbrick", PowerRootWarCry },
{ "fire_wall_aura.sbrick", PowerRootFireWall },
{ "thorn_wall_aura.sbrick", PowerRootThornWall },
{ "water_wall_aura.sbrick", PowerRootWaterWall },
{ "lightning_wall_aura.sbrick", PowerRootLightningWall },
{ "chg_charac.sbrick", PowerChgCharac }, { "chg_charac.sbrick", PowerChgCharac },
{ "mod_defense.sbrick", PowerModDefenseSkill }, { "mod_defense.sbrick", PowerModDefenseSkill },
{ "mod_dodge.sbrick", PowerModDodgeSkill }, { "mod_dodge.sbrick", PowerModDodgeSkill },

Loading…
Cancel
Save