Merge with experimental-ui-scaling

--HG--
branch : develop
This commit is contained in:
Nimetu 2018-11-23 12:05:46 +02:00
commit 8a18a5dade
22 changed files with 505 additions and 187 deletions

View file

@ -38,6 +38,16 @@ namespace NLGUI
class IActionHandler;
class CGroupParagraph;
/**
* Interface for UI scale change event
*/
class IInterfaceScaleWatcher
{
public:
virtual ~IInterfaceScaleWatcher(){}
virtual void onInterfaceScaleChanged()=0;
};
/**
* A visitor to walk a tree of interface elements and apply a teartment on them.
*
@ -66,7 +76,7 @@ namespace NLGUI
* \author Nevrax France
* \date 2002
*/
class CInterfaceElement : public CReflectableRefPtrTarget, public NLMISC::IStreamable
class CInterfaceElement : public IInterfaceScaleWatcher, public CReflectableRefPtrTarget, public NLMISC::IStreamable
{
public:
@ -409,6 +419,10 @@ namespace NLGUI
*/
virtual void onInvalidateContent() {}
/* Element UI scale change event callback
*/
virtual void onInterfaceScaleChanged() {}
// called by interfaceManager for master window only
void resetInvalidCoords();

View file

@ -176,6 +176,13 @@ namespace NLGUI
*/
void getScreenOOSize (float &oow, float &ooh);
/*
* UI scaling
*/
void setInterfaceScale(float scale, sint32 width = 0, sint32 height = 0);
float getInterfaceScale() const { return _InterfaceScale; }
void setBilinearFiltering(bool b) { _Bilinear = b; }
/*
* is the Screen minimized?
*/
@ -185,7 +192,7 @@ namespace NLGUI
* drawBitmap : this is the interface with all the views
*
*/
void drawRotFlipBitmap (sint layerId, sint32 x, sint32 y, sint32 width, sint32 height, uint8 rot, bool flipv,
void drawRotFlipBitmap (sint layerId, float x, float y, float width, float height, uint8 rot, bool flipv,
sint32 nTxId, const NLMISC::CRGBA &col = NLMISC::CRGBA(255,255,255,255));
/*
@ -526,6 +533,14 @@ namespace NLGUI
float _OneOverScreenW, _OneOverScreenH;
bool _IsMinimized;
// UI scaling
float _InterfaceScale;
float _InterfaceUserScale;
sint32 _InterfaceBaseW, _InterfaceBaseH;
sint32 _EffectiveScreenW, _EffectiveScreenH;
bool _Bilinear;
void updateInterfaceScale();
//map linking a uint to a bitmap. Used to display figurs
std::vector<sint32> _IndexesToTextureIds;
@ -596,7 +611,6 @@ namespace NLGUI
/// Set of hw cursor images
static std::set< std::string > *hwCursors;
static float hwCursorScale;
};

View file

@ -70,6 +70,7 @@ namespace NLGUI
virtual void checkCoords();
virtual void updateCoords();
virtual void onAddToGroup();
virtual void onInterfaceScaleChanged();
/// From CInterfaceElement
sint32 getMaxUsedW() const;
@ -90,6 +91,7 @@ namespace NLGUI
void setShadowColor (const NLMISC::CRGBA &color);
void setShadowOffset (sint x, sint y);
void setLineMaxW (sint nMaxW, bool invalidate=true);
void setOverflowText(const ucstring &text) { _OverflowText = text; }
void setMultiLine (bool bMultiLine);
void setMultiLineSpace (sint nMultiLineSpace);
void setMultiLineMaxWOnly (bool state);
@ -115,6 +117,7 @@ namespace NLGUI
NLMISC::CRGBA getShadowColor() { return _ShadowColor; }
void getShadowOffset(sint &x, sint &y) { x = _ShadowX; y = _ShadowY; }
sint getLineMaxW() const { return _LineMaxW; }
ucstring getOverflowText() const { return _OverflowText; }
bool getMultiLine() const { return _MultiLine; }
sint getMultiLineSpace() const { return _MultiLineSpace; }
bool getMultiLineMaxWOnly() const { return _MultiLineMaxWOnly; }
@ -128,6 +131,8 @@ namespace NLGUI
uint getFontHeight() const;
// get current font leg height, in pixels
uint getFontLegHeight() const;
// get current line height, in pixels
float getLineHeight() const;
// Set the display mode (supported with multiline only for now)
void setTextMode(TTextMode mode);
TTextMode getTextMode() const { return _TextMode; }
@ -148,11 +153,11 @@ namespace NLGUI
* When looking at standard edit box, we see that if a line is split accross to line with no
* This also returns the height of the line
*/
void getCharacterPositionFromIndex(sint index, bool lineEnd, sint &x, sint &y, sint &height) const;
void getCharacterPositionFromIndex(sint index, bool lineEnd, float &x, float &y, float &height) const;
/** From a coordinate relative to the BR BR corner of the text, return the index of a character.
* If no character is found at the given position, the closest character is returned (first or last character, for the line or the whole text)
*/
void getCharacterIndexFromPosition(sint x, sint y, uint &index, bool &lineEnd) const;
void getCharacterIndexFromPosition(float x, float y, uint &index, bool &lineEnd) const;
/** From a character index, get the index of the line it belongs to, or -1 if the index is invalid
* \param cursorDisplayedAtEndOfPreviousLine true if the cursor is displayed at the end of the previous line that match its index
*/
@ -238,12 +243,14 @@ namespace NLGUI
bool _Embolden;
bool _Oblique;
// width of the font in pixel. Just a Hint for tabing format (computed with '_')
uint _FontWidth;
float _FontWidth;
// height of the font in pixel.
// use getFontHeight
uint _FontHeight;
uint _FontLegHeight;
float _FontHeight;
float _FontLegHeight;
float _SpaceWidth;
/// last UI scale used to calculate font size
float _Scale;
/// the text color
NLMISC::CRGBA _Color;
/// the shadow mode
@ -260,6 +267,7 @@ namespace NLGUI
sint32 _LineMaxW;
/// For single line, true if the text is clamped (ie displayed with "...")
bool _SingleLineTextClamped;
ucstring _OverflowText;
/// Multiple lines handling
bool _MultiLine;
@ -341,8 +349,8 @@ namespace NLGUI
// Clear the line & remove text contexts
void clear(NL3D::UTextContext &textContext);
// Add a new word (and its context) in the line + a number of spaces to append at the end of the line
void addWord(const ucstring &word, uint numSpaces, const CFormatInfo &wordFormat, uint fontWidth, NL3D::UTextContext &textContext);
void addWord(const CWord &word, uint fontWidth);
void addWord(const ucstring &word, uint numSpaces, const CFormatInfo &wordFormat, float fontWidth, NL3D::UTextContext &textContext);
void addWord(const CWord &word, float fontWidth);
uint getNumWords() const { return (uint)_Words.size(); }
CWord &getWord(uint index) { return _Words[index]; }
float getSpaceWidth() const { return _SpaceWidth; }
@ -402,7 +410,7 @@ namespace NLGUI
uint _TextSelectionEnd;
// First line X coordinate
sint _FirstLineX;
float _FirstLineX;
/// Dynamic tooltips
std::vector<CCtrlToolTip*> _Tooltips;

View file

@ -49,6 +49,7 @@ namespace NLGUI
class CProcedure;
class IEditorSelectionWatcher;
class IWidgetAdditionWatcher;
class IInterfaceScaleWatcher;
/**
GUI Widget Manager
@ -530,6 +531,11 @@ namespace NLGUI
bool unGroupSelection();
void setMultiSelection( bool b ){ multiSelection = b; }
float getInterfaceScale() const { return _InterfaceScale; }
void notifyInterfaceScaleWatchers();
void registerInterfaceScaleWatcher(IInterfaceScaleWatcher *watcher);
void unregisterInterfaceScaleWatcher(IInterfaceScaleWatcher *watcher);
bool createNewGUI( const std::string &project, const std::string &window );
private:
@ -615,6 +621,7 @@ namespace NLGUI
uint32 _ScreenH;
uint32 _ScreenW;
float _InterfaceScale;
std::vector< CInterfaceAnim* > activeAnims;
@ -622,6 +629,7 @@ namespace NLGUI
std::vector< IOnWidgetsDrawnHandler* > onWidgetsDrawnHandlers;
std::vector< IEditorSelectionWatcher* > selectionWatchers;
std::vector< IWidgetWatcher* > widgetWatchers;
std::vector< IInterfaceScaleWatcher* > scaleWatchers;
std::vector< std::string > editorSelection;
bool _GroupSelection;

View file

@ -702,9 +702,9 @@ namespace NLGUI
sint32 maxPos= max(_CursorPos, _SelectCursorPos) + (sint32)_Prompt.length();
// get its position on screen
sint cxMinPos, cyMinPos;
sint cxMaxPos, cyMaxPos;
sint height;
float cxMinPos, cyMinPos;
float cxMaxPos, cyMaxPos;
float height;
_ViewText->getCharacterPositionFromIndex(minPos, false, cxMinPos, cyMinPos, height);
_ViewText->getCharacterPositionFromIndex(maxPos, false, cxMaxPos, cyMaxPos, height);
@ -755,8 +755,8 @@ namespace NLGUI
if (_BlinkState) // is the cursor shown ?
{
// get its position on screen
sint cx, cy;
sint height;
float cx, cy;
float height;
_ViewText->getCharacterPositionFromIndex(_CursorPos + (sint)_Prompt.length(), _CursorAtPreviousLineEnd, cx, cy, height);
// display the cursor
// get the texture for the cursor
@ -1482,7 +1482,7 @@ namespace NLGUI
if (_ViewText->getWReal() > _WReal)
{
// Check if cursor visible
sint xCursVT, xCurs, yTmp, hTmp;
float xCursVT, xCurs, yTmp, hTmp;
// Get the cursor pos from the BL of the viewtext
_ViewText->getCharacterPositionFromIndex(_CursorPos+(sint)_Prompt.size(), false, xCursVT, yTmp, hTmp);
// Get the cursor pos from the BL of the edit box

View file

@ -96,8 +96,23 @@ namespace NLGUI
if(w!=0 && h!=0)
{
_IsMinimized= false;
if (w != _ScreenW || h != _ScreenH)
{
_ScreenW = w;
_ScreenH = h;
updateInterfaceScale();
}
}
else
{
// Keep old coordinates (suppose resolution won't change, even if typically false wen we swithch from outgame to ingame)
_IsMinimized= true;
}
}
void CViewRenderer::updateInterfaceScale()
{
if(_ScreenW>0)
_OneOverScreenW = 1.0f / (float)_ScreenW;
else
@ -106,11 +121,27 @@ namespace NLGUI
_OneOverScreenH = 1.0f / (float)_ScreenH;
else
_OneOverScreenH = 1000;
_InterfaceScale = _InterfaceUserScale;
if (_InterfaceBaseW > 0 && _InterfaceBaseH > 0)
{
float wRatio = (float)_ScreenW / _InterfaceBaseW;
float rRatio = (float)_ScreenH / _InterfaceBaseH;
_InterfaceScale *= std::min(wRatio, rRatio);
}
if (_InterfaceScale != 1.0f)
{
_OneOverScreenW *= _InterfaceScale;
_OneOverScreenH *= _InterfaceScale;
_EffectiveScreenW = sint(_ScreenW / _InterfaceScale);
_EffectiveScreenH = sint(_ScreenH / _InterfaceScale);
}
else
{
// Keep old coordinates (suppose resolution won't change, even if typically false wen we swithch from outgame to ingame)
_IsMinimized= true;
_EffectiveScreenW = _ScreenW;
_EffectiveScreenH = _ScreenH;
}
}
@ -120,8 +151,8 @@ namespace NLGUI
*/
void CViewRenderer::getScreenSize (uint32 &w, uint32 &h)
{
w = _ScreenW;
h = _ScreenH;
w = _EffectiveScreenW;
h = _EffectiveScreenH;
}
/*
@ -133,6 +164,20 @@ namespace NLGUI
ooh= _OneOverScreenH;
}
void CViewRenderer::setInterfaceScale(float scale, sint32 width/*=0*/, sint32 height/*=0*/)
{
// prevent #div/0
if (sint(scale*100) > 0)
_InterfaceUserScale = scale;
else
_InterfaceUserScale = 1.0f;
_InterfaceBaseW = width;
_InterfaceBaseH = height;
updateInterfaceScale();
}
void CViewRenderer::setup()
{
_ClipX = _ClipY = 0;
@ -140,8 +185,10 @@ namespace NLGUI
_ClipH = 600;
_ScreenW = 800;
_ScreenH = 600;
_OneOverScreenW= 1.0f / (float)_ScreenW;
_OneOverScreenH= 1.0f / (float)_ScreenH;
_InterfaceScale = 1.0f;
_InterfaceUserScale = 1.0f;
_InterfaceBaseW = 0;
_InterfaceBaseH = 0;
_IsMinimized= false;
_WFigurTexture= 0;
_HFigurTexture= 0;
@ -157,6 +204,9 @@ namespace NLGUI
_EmptyLayer[i]= true;
}
_BlankGlobalTexture = NULL;
_Bilinear = false;
updateInterfaceScale();
}
@ -499,7 +549,7 @@ namespace NLGUI
/*
* drawBitmap
*/
void CViewRenderer::drawRotFlipBitmap (sint layerId, sint32 x, sint32 y, sint32 width, sint32 height,
void CViewRenderer::drawRotFlipBitmap (sint layerId, float x, float y, float width, float height,
uint8 rot, bool flipv, sint32 nTxId, const CRGBA &col)
{
if (width <= 0 || height <= 0) return;
@ -1283,7 +1333,7 @@ namespace NLGUI
_Material.setTexture(0, ite->Texture);
// Special Case if _WorldSpaceTransformation and _WorldSpaceScale, enable bilinear
if(_WorldSpaceTransformation && _WorldSpaceScale)
if(_Bilinear || (_WorldSpaceTransformation && _WorldSpaceScale))
ite->Texture->setFilterMode(UTexture::Linear, UTexture::LinearMipMapOff);
// draw quads and empty list
@ -1300,7 +1350,7 @@ namespace NLGUI
}
// Special Case if _WorldSpaceTransformation and _WorldSpaceScale, reset
if(_WorldSpaceTransformation && _WorldSpaceScale)
if(_Bilinear || (_WorldSpaceTransformation && _WorldSpaceScale))
ite->Texture->setFilterMode(UTexture::Nearest, UTexture::NearestMipMapOff);
}
if (!layer.FilteredAlphaBlendedQuads.empty() ||
@ -1942,6 +1992,25 @@ namespace NLGUI
void CViewRenderer::drawText (sint layerId, float x, float y, uint wordIndex, float xmin, float ymin, float xmax, float ymax, UTextContext &textContext)
{
xmin = xmin * _OneOverScreenW;
ymin = ymin * _OneOverScreenH;
xmax = xmax * _OneOverScreenW;
ymax = ymax * _OneOverScreenH;
if (_InterfaceScale != 1.0f && _InterfaceScale != 2.0f)
{
// align to screen pixel
x *= _OneOverScreenW * _ScreenW;
y *= _OneOverScreenH * _ScreenH;
x = floorf(x) * 1.f / (float) _ScreenW;
y = floorf(y) * 1.f / (float) _ScreenH;
}
else
{
x = floorf(x) * _OneOverScreenW;
y = floorf(y) * _OneOverScreenH;
}
if (_WorldSpaceTransformation)
{
textContext.printClipAtUnProjected(*getStringRenderBuffer(layerId), _CameraFrustum, _WorldSpaceMatrix, x, y, _CurrentZ, wordIndex, xmin, ymin, xmax, ymax);

View file

@ -86,6 +86,7 @@ namespace NLGUI
_MultiMaxLine = 0;
_Index = 0xFFFFFFFF;
_Scale = CWidgetManager::getInstance()->getInterfaceScale();
_FontWidth= 0;
_FontHeight = 0;
_FontLegHeight = 0;
@ -104,6 +105,7 @@ namespace NLGUI
_AutoClamp = false;
_ClampRight = true; // clamp on the right of the text
_OverflowText = "...";
_LetterColors = NULL;
_Setuped= false;
@ -118,6 +120,8 @@ namespace NLGUI
:CViewBase(param)
{
setupDefault ();
CWidgetManager::getInstance()->registerInterfaceScaleWatcher(this);
}
///constructor
@ -135,11 +139,15 @@ namespace NLGUI
_ShadowOutline = ShadowOutline;
setText(Text);
computeFontSize ();
CWidgetManager::getInstance()->registerInterfaceScaleWatcher(this);
}
// ***************************************************************************
CViewText::~CViewText()
{
CWidgetManager::getInstance()->unregisterInterfaceScaleWatcher(this);
if (_Index != 0xFFFFFFFF)
CViewRenderer::getTextContext(_FontName)->erase (_Index);
clearLines();
@ -912,8 +920,9 @@ namespace NLGUI
// ***************************************************************************
sint CViewText::getCurrentMultiLineMaxW() const
{
sint maxw = ceilf(_LineMaxW * _Scale);
if(_MultiLineMaxWOnly)
return _LineMaxW;
return maxw;
else
{
sint offset = (sint)_XReal - (sint)_Parent->getXReal();
@ -978,6 +987,31 @@ namespace NLGUI
CViewRenderer &rVR = *CViewRenderer::getInstance();
#if 0
//rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, _WReal, _HReal, 0, false, rVR.getBlankTextureId(), CRGBA(64,64,64,255));
// debug text with mouse hover
if(CWidgetManager::getInstance()->getPointer())
{
// but must check first if mouse is over
sint32 x = CWidgetManager::getInstance()->getPointer()->getX();
sint32 y = CWidgetManager::getInstance()->getPointer()->getY();
bool mouseIn;
// use parent clip or self clip?
if(_OverExtendViewTextUseParentRect)
mouseIn= _Parent && _Parent->isIn(x,y);
else
mouseIn= isIn(x,y);
// if the mouse cursor is in the clip area
if(mouseIn) {
rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, _WReal, 1, 0, false, rVR.getBlankTextureId(), CRGBA(200,200,200,255));
rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal+_HReal, _WReal, 1, 0, false, rVR.getBlankTextureId(), CRGBA(200,200,200,255));
rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, 1, _HReal, 0, false, rVR.getBlankTextureId(), CRGBA(200,200,200,255));
rVR.drawRotFlipBitmap (_RenderLayer, _XReal+_WReal, _YReal, 1, _HReal, 0, false, rVR.getBlankTextureId(), CRGBA(200,200,200,255));
}
}
#endif
// *** Out Of Clip?
sint32 ClipX, ClipY, ClipW, ClipH;
rVR.getClipWindow (ClipX, ClipY, ClipW, ClipH);
@ -999,12 +1033,8 @@ namespace NLGUI
}
// *** Screen Minimized?
uint32 w, h;
float oow, ooh;
rVR.getScreenSize (w, h);
if (rVR.isMinimized())
return;
rVR.getScreenOOSize (oow, ooh);
NL3D::UTextContext *TextContext = CViewRenderer::getTextContext(_FontName);
@ -1025,6 +1055,8 @@ namespace NLGUI
shcol.A = (uint8)(((sint)shcol.A*((sint)CWidgetManager::getInstance()->getGlobalColorForContent().A+1))>>8);
}
float oow, ooh;
rVR.getScreenOOSize (oow, ooh);
// *** Draw multiline
if ((_MultiLine)&&(_Parent != NULL))
@ -1036,23 +1068,16 @@ namespace NLGUI
TextContext->setShadeOutline (_ShadowOutline);
TextContext->setShadeColor (shcol);
TextContext->setShadeExtent (_ShadowX*oow, _ShadowY*ooh);
TextContext->setFontSize (_FontSize);
TextContext->setFontSize (_FontSize*_Scale);
TextContext->setEmbolden (_Embolden);
TextContext->setOblique (_Oblique);
float y = (float)(_YReal) * ooh; // y is expressed in scree, coordinates [0..1]
//y += _LinesInfos[_LinesInfos.size()-1].StringLine / h;
// Y is the base line of the string, so it must be grown up.
y += (float)_FontLegHeight * ooh;
sint y_line = _YReal+_FontLegHeight-2;
float y = _YReal * _Scale + _FontLegHeight;
if (_MultiMinLine > _Lines.size())
{
uint dy = getMultiMinOffsetY();
y += dy * ooh;
y_line += dy;
y += getMultiMinOffsetY() * _Scale;
}
// special selection code
@ -1093,7 +1118,7 @@ namespace NLGUI
{
CLine &currLine = *_Lines[i];
// current x position
float px = (float) (_XReal + ((i==0) ? (sint)_FirstLineX : 0));
float px = (float) (_XReal * _Scale + ((i==0) ? (sint)_FirstLineX : 0));
// draw each words of the line
for(uint k = 0; k < currLine.getNumWords(); ++k)
{
@ -1120,25 +1145,25 @@ namespace NLGUI
px += firstSpace;
// skip tabulation before current word
if(currWord.Format.TabX)
px= max(px, (float)(_XReal + currWord.Format.TabX*_FontWidth));
px= max(px, (float)(_XReal * _Scale + currWord.Format.TabX*_FontWidth));
// draw. We take floorf px to avoid filtering of letters that are not located on a pixel boundary
rVR.drawText (_RenderLayer, floorf(px) * oow, y, currWord.Index, (float)ClipX * oow, (float)ClipY * ooh,
(float)(ClipX+ClipW) * oow, (float)(ClipY+ClipH) * ooh, *TextContext);
float fx = px / _Scale;
float fy = y / _Scale;
rVR.drawText (_RenderLayer, fx, fy, currWord.Index, ClipX, ClipY, ClipX+ClipW, ClipY+ClipH, *TextContext);
// Draw a line
if (_Underlined)
rVR.drawRotFlipBitmap (_RenderLayer, (sint)floorf(px), y_line, line_width, 1, 0, false, rVR.getBlankTextureId(), col);
rVR.drawRotFlipBitmap (_RenderLayer, fx, fy - _FontLegHeight*0.6f / _Scale, line_width / _Scale, 1.0f / _Scale, 0, false, rVR.getBlankTextureId(), col);
if (_StrikeThrough)
rVR.drawRotFlipBitmap (_RenderLayer, (sint)floorf(px), y_line + (_FontHeight / 2), line_width, 1, 0, false, rVR.getBlankTextureId(), col);
rVR.drawRotFlipBitmap (_RenderLayer, fx, fy + _FontHeight*0.2f / _Scale, line_width / _Scale, 1.0f / _Scale, 0, false, rVR.getBlankTextureId(), col);
// skip word
px += currWord.Info.StringWidth;
}
// go one line up
y += (_FontHeight + _MultiLineSpace) * ooh;
y_line += _FontHeight+_MultiLineSpace;
y += (_FontHeight + _MultiLineSpace * _Scale);
}
// reset selection
@ -1164,22 +1189,17 @@ namespace NLGUI
TextContext->setShadeOutline (_ShadowOutline);
TextContext->setShadeColor (shcol);
TextContext->setShadeExtent (_ShadowX*oow, _ShadowY*ooh);
TextContext->setFontSize (_FontSize);
TextContext->setFontSize (_FontSize*_Scale);
TextContext->setEmbolden (_Embolden);
TextContext->setOblique (_Oblique);
if(_LetterColors!=NULL && !TextContext->isSameLetterColors(_LetterColors, _Index))
{
TextContext->setLetterColors(_LetterColors, _Index);
}
float x = (float)(_XReal) * oow;
float y = (float)(_YReal) * ooh;
// Y is the base line of the string, so it must be grown up.
y += (float)_FontLegHeight * ooh;
float y = _YReal * _Scale + _FontLegHeight;
// special selection code
if(_TextSelection)
@ -1190,15 +1210,14 @@ namespace NLGUI
TextContext->setStringColor(_Index, col);
// draw
rVR.drawText (_RenderLayer, x, y, _Index, (float)ClipX * oow, (float)ClipY * ooh,
(float)(ClipX+ClipW) * oow, (float)(ClipY+ClipH) * ooh, *TextContext);
rVR.drawText (_RenderLayer, _XReal, y / _Scale, _Index, ClipX, ClipY, ClipX+ClipW, ClipY+ClipH, *TextContext);
// Draw a line
if (_Underlined)
rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal+_FontLegHeight-2, _WReal, 1, 0, false, rVR.getBlankTextureId(), col);
rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal - _FontLegHeight*0.3f/_Scale, _WReal, 1, 0, false, rVR.getBlankTextureId(), col);
if (_StrikeThrough)
rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal+(_FontLegHeight/2), _WReal, 1, 0, false, rVR.getBlankTextureId(), col);
rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal + _FontHeight*0.2f / _Scale, _WReal, 1, 0, false, rVR.getBlankTextureId(), col);
// reset selection
if(_TextSelection)
@ -1247,7 +1266,6 @@ namespace NLGUI
}
}
}
}
// ***************************************************************************
@ -1409,7 +1427,7 @@ namespace NLGUI
sint32 value;
if(CLuaIHM::popSINT32(ls, value))
{
setLineMaxW(value);
setLineMaxW(ceilf(value / _Scale));
}
return 0;
}
@ -1445,19 +1463,25 @@ namespace NLGUI
// ***************************************************************************
uint CViewText::getFontWidth() const
{
return _FontWidth;
return _FontWidth / _Scale;
}
// ***************************************************************************
uint CViewText::getFontHeight() const
{
return _FontHeight;
return _FontHeight / _Scale;
}
// ***************************************************************************
uint CViewText::getFontLegHeight() const
{
return _FontLegHeight;
return _FontLegHeight / _Scale;
}
// ***************************************************************************
float CViewText::getLineHeight() const
{
return _FontHeight / _Scale + _MultiLineSpace;
}
// ***************************************************************************
@ -1468,7 +1492,7 @@ namespace NLGUI
{
// first line is always present even if _Lines is empty
uint nbLines = _MultiMinLine - std::max((sint)1, (sint)_Lines.size());
dy = nbLines * _FontHeight + (nbLines - 1) * _MultiLineSpace;
dy = (nbLines * _FontHeight + (nbLines - 1) * _MultiLineSpace * _Scale) / _Scale;
}
return dy;
}
@ -1500,11 +1524,12 @@ namespace NLGUI
ucstring ucCurrentWord;
CFormatInfo wordFormat;
// line state
float rWidthCurrentLine = 0, rWidthLetter;
float rWidthCurrentLine = 0;
bool linePushed= false;
// for all the text
uint textSize= (uint)_Text.size();
uint formatTagIndex= 0;
nMaxWidth *= _Scale;
for (i = 0; i < textSize; ++i)
{
if(isFormatTagChange(i, formatTagIndex))
@ -1537,21 +1562,20 @@ namespace NLGUI
ucstring ucStrLetter;
ucStrLetter= ucLetter;
si = TextContext->getStringInfo (ucStrLetter);
rWidthLetter = (si.StringWidth);
if ((rWidthCurrentLine + rWidthLetter) > nMaxWidth)
if ((rWidthCurrentLine + si.StringWidth) > nMaxWidth)
{
flushWordInLine(ucCurrentWord, linePushed, wordFormat);
// reset line state, and begin with the cut letter
linePushed= false;
rWidthCurrentLine = rWidthLetter;
rWidthCurrentLine = si.StringWidth;
ucCurrentWord = ucLetter;
}
else
{
// Grow the current word
ucCurrentWord += ucLetter;
rWidthCurrentLine += rWidthLetter;
rWidthCurrentLine += si.StringWidth;
}
}
}
@ -1625,12 +1649,13 @@ namespace NLGUI
CFormatInfo wordFormat;
uint formatTagIndex= 0;
//
nMaxWidth *= _Scale;
while (currPos != _Text.length())
{
TCharPos spaceEnd;
TCharPos wordEnd;
uint numSpaces;
float newLineWidth;
float newLineWidth = 0;
breakLine = false;
//
if (_Text[currPos] == (ucchar) '\n')
@ -1903,7 +1928,7 @@ namespace NLGUI
TextContext->setHotSpot (UTextContext::BottomLeft);
TextContext->setShaded (_Shadow);
TextContext->setShadeOutline (_ShadowOutline);
TextContext->setFontSize (_FontSize);
TextContext->setFontSize (_FontSize*_Scale);
TextContext->setEmbolden (_Embolden);
TextContext->setOblique (_Oblique);
@ -1912,7 +1937,7 @@ namespace NLGUI
if ((_MultiLine)&&(_Parent != NULL))
{
sint nMaxWidth = getCurrentMultiLineMaxW();
float nMaxWidth = getCurrentMultiLineMaxW();
_LastMultiLineMaxW = nMaxWidth;
clearLines();
if (nMaxWidth <= 0)
@ -1935,26 +1960,30 @@ namespace NLGUI
_Lines.back()->clear(*TextContext);
_Lines.pop_back();
}
if (_OverflowText.size() > 0)
{
_Lines.pop_back();
CViewText::CLine *endLine = new CViewText::CLine;
CViewText::CWord w;
w.build(string("..."), *TextContext);
w.build(_OverflowText, *TextContext);
endLine->addWord(w, _FontWidth);
_Lines.push_back(TLineSPtr(endLine));
}
}
// Calculate size
float rMultiLineSpace = _MultiLineSpace * _Scale;
float rTotalW = 0;
for (uint i = 0; i < _Lines.size(); ++i)
{
rTotalW = std::max(_Lines[i]->getWidth() + ((i==0)?_FirstLineX:0), rTotalW);
}
_W = (sint)rTotalW;
_H = std::max(_FontHeight, uint(_FontHeight * _Lines.size() + std::max(0, sint(_Lines.size()) - 1) * _MultiLineSpace));
_W = (sint)ceilf(rTotalW / _Scale);
_H = std::max(_FontHeight / _Scale, ceilf((_FontHeight * _Lines.size() + std::max(0, sint(_Lines.size()) - 1) * rMultiLineSpace) / _Scale));
// See if we should pretend to have at least X lines
if (_MultiMinLine > 1)
_H = std::max(_H, sint(_FontHeight * _MultiMinLine + (_MultiMinLine - 1) * _MultiLineSpace));
_H = std::max(_H, sint((_FontHeight * _MultiMinLine + (_MultiMinLine - 1) * rMultiLineSpace)/_Scale));
// Compute tooltips size
if (!_Tooltips.empty())
@ -1963,7 +1992,6 @@ namespace NLGUI
for (uint j=0 ; j<_Lines[i]->getNumWords() ; ++j)
{
CWord word = _Lines[i]->getWord(j);
// float w = _Lines[i]->getWidth();
if (word.Format.IndexTt != -1)
{
@ -1971,7 +1999,7 @@ namespace NLGUI
{
CCtrlToolTip *pTooltip = _Tooltips[word.Format.IndexTt];
sint y = (sint) ((_FontHeight + _MultiLineSpace) * (_Lines.size() - i - 1));
sint y = (sint) ceilf(((_FontHeight + rMultiLineSpace) * (_Lines.size() - i - 1))/_Scale);
pTooltip->setX(0);
pTooltip->setY(y);
@ -1990,10 +2018,10 @@ namespace NLGUI
// Common case: no W clamp
_Index = TextContext->textPush (_Text);
_Info = TextContext->getStringInfo (_Index);
_W = (sint)(_Info.StringWidth);
_W = (sint)ceilf(_Info.StringWidth / _Scale);
// Rare case: clamp W => recompute slowly, cut letters
if(_W>_LineMaxW)
if(_Info.StringWidth > _LineMaxW)
{
TextContext->erase (_Index);
@ -2001,10 +2029,16 @@ namespace NLGUI
UTextContext::CStringInfo si;
ucstring ucCurrentLine;
ucCurrentLine.reserve(_Text.size());
// Append ... to the end of line
si = TextContext->getStringInfo (ucstring("..."));
float dotWidth= si.StringWidth;
float rWidthCurrentLine = 0, rWidthLetter;
float dotWidth = 0.f;
if (_OverflowText.size() > 0)
{
si = TextContext->getStringInfo (ucstring(_OverflowText));
dotWidth = si.StringWidth;
}
float rWidthCurrentLine = 0;
// for all the text
if (_ClampRight)
{
@ -2014,8 +2048,7 @@ namespace NLGUI
ucstring ucStrLetter;
ucStrLetter= ucLetter;
si = TextContext->getStringInfo (ucStrLetter);
rWidthLetter = (si.StringWidth);
if ((rWidthCurrentLine + rWidthLetter + dotWidth) > _LineMaxW)
if ((rWidthCurrentLine + si.StringWidth + dotWidth) > _LineMaxW)
{
break;
}
@ -2023,12 +2056,15 @@ namespace NLGUI
{
// Grow the current line
ucCurrentLine += ucLetter;
rWidthCurrentLine += rWidthLetter;
rWidthCurrentLine += si.StringWidth;
}
}
// Add the dots
ucCurrentLine+= "...";
if (_OverflowText.size() > 0)
{
ucCurrentLine += _OverflowText;
}
}
else
{
@ -2038,8 +2074,7 @@ namespace NLGUI
ucstring ucStrLetter;
ucStrLetter= ucLetter;
si = TextContext->getStringInfo (ucStrLetter);
rWidthLetter = (si.StringWidth);
if ((rWidthCurrentLine + rWidthLetter + dotWidth) > _LineMaxW)
if ((rWidthCurrentLine + si.StringWidth + dotWidth) > _LineMaxW)
{
break;
}
@ -2047,24 +2082,27 @@ namespace NLGUI
{
// Grow the current line
ucCurrentLine = ucLetter + ucCurrentLine;
rWidthCurrentLine += rWidthLetter;
rWidthCurrentLine += si.StringWidth;
}
}
// Add the dots
ucCurrentLine = "..." + ucCurrentLine;
if (_OverflowText.size() > 0)
{
ucCurrentLine = _OverflowText + ucCurrentLine;
}
}
// And so setup this trunc text
_Index = TextContext->textPush (ucCurrentLine);
_Info = TextContext->getStringInfo (_Index);
_W = (sint)(_Info.StringWidth);
_W = (sint)ceilf(_Info.StringWidth / _Scale);
_SingleLineTextClamped= true;
}
// same height always
_H = _FontHeight;
_H = (sint)ceilf(_FontHeight / _Scale);
}
_InvalidTextContext= false;
@ -2223,28 +2261,29 @@ namespace NLGUI
}
// ***************************************************************************
void CViewText::getCharacterPositionFromIndex(sint index, bool cursorAtPreviousLineEnd, sint &x, sint &y, sint &height) const
void CViewText::getCharacterPositionFromIndex(sint index, bool cursorAtPreviousLineEnd, float &x, float &y, float &height) const
{
NLMISC::clamp(index, 0, (sint) _Text.length());
NL3D::UTextContext *TextContext = CViewRenderer::getTextContext(_FontName);
TextContext->setHotSpot (UTextContext::BottomLeft);
TextContext->setShaded (_Shadow);
TextContext->setShadeOutline (_ShadowOutline);
TextContext->setFontSize (_FontSize);
TextContext->setFontSize (_FontSize*_Scale);
TextContext->setEmbolden (_Embolden);
TextContext->setOblique (_Oblique);
// CViewRenderer &rVR = *CViewRenderer::getInstance();
height = getFontHeight();
height = getLineHeight();
//
if (_MultiLine)
{
uint dy = getMultiMinOffsetY();
float fx, fy;
float dy = getMultiMinOffsetY() * _Scale;
float nMaxWidth = getCurrentMultiLineMaxW() * _Scale;
uint charIndex = 0;
// special case for end of text
if (index == (sint) _Text.length())
{
y = dy;
fy = dy;
if (_Lines.empty())
{
x = 0;
@ -2252,10 +2291,12 @@ namespace NLGUI
else
{
CLine &lastLine = *_Lines.back();
x = (sint) (lastLine.getWidth() + lastLine.getEndSpaces() * lastLine.getSpaceWidth());
sint nMaxWidth = getCurrentMultiLineMaxW();
x = std::min(x, nMaxWidth);
fx = lastLine.getWidth() + lastLine.getEndSpaces() * lastLine.getSpaceWidth();
fx = std::min(fx, nMaxWidth);
}
x = fx / _Scale;
y = fy / _Scale;
return;
}
for(sint i = 0; i < (sint) _Lines.size(); ++i)
@ -2264,10 +2305,12 @@ namespace NLGUI
{
// should display the character at the end of previous line
CLine &currLine = *_Lines[i - 1];
y = (sint) ((_FontHeight + _MultiLineSpace) * (_Lines.size() - i) + dy);
x = (sint) (currLine.getWidth() + currLine.getEndSpaces() * currLine.getSpaceWidth());
sint nMaxWidth = getCurrentMultiLineMaxW();
x = std::min(x, nMaxWidth);
fy = (_FontHeight + _MultiLineSpace * _Scale) * (_Lines.size() - i) + dy;
fx = currLine.getWidth() + currLine.getEndSpaces() * currLine.getSpaceWidth();
fx = std::min(fx, nMaxWidth);
x = fx / _Scale;
y = fy / _Scale;
return;
}
CLine &currLine = *_Lines[i];
@ -2275,14 +2318,16 @@ namespace NLGUI
if ((sint) newCharIndex > index)
{
// ok, this line contains the character, now, see which word contains it.
y = (sint) ((_FontHeight + _MultiLineSpace) * (_Lines.size() - 1 - i) + dy);
fy = (_FontHeight + _MultiLineSpace * _Scale) * (_Lines.size() - 1 - i) + dy;
// see if the index is in the spaces at the end of line
if (index - charIndex >= currLine.getNumChars())
{
uint numSpaces = index - charIndex - currLine.getNumChars();
x = (sint) (currLine.getWidth() + numSpaces * _SpaceWidth);
sint nMaxWidth = getCurrentMultiLineMaxW();
x = std::min(x, nMaxWidth);
fx = currLine.getWidth() + numSpaces * _SpaceWidth;
fx = std::min(fx, nMaxWidth);
x = fx / _Scale;
y = fy / _Scale;
return;
}
// now, search containing word in current line
@ -2300,15 +2345,19 @@ namespace NLGUI
ucstring subStr = currWord.Text.substr(0, index - charIndex - currWord.NumSpaces);
// compute the size
UTextContext::CStringInfo si = TextContext->getStringInfo(subStr);
x = (sint) (px + si.StringWidth + currWord.NumSpaces * currLine.getSpaceWidth());
height = getFontHeight();
fx = px + si.StringWidth + currWord.NumSpaces * currLine.getSpaceWidth();
x = fx / _Scale;
y = fy / _Scale;
return;
}
else
{
// character is in the spaces preceding the word
x = (sint) (px + currLine.getSpaceWidth() * (index - charIndex));
height = getFontHeight();
fx = px + currLine.getSpaceWidth() * (index - charIndex);
x = fx / _Scale;
y = fy / _Scale;
return;
}
}
@ -2327,15 +2376,16 @@ namespace NLGUI
// compute the size
UTextContext::CStringInfo si = TextContext->getStringInfo(subStr);
y = 0;
x = (sint) si.StringWidth;
x = (sint) ceilf(si.StringWidth / _Scale);
}
}
// ***************************************************************************
// Tool fct : From a word and a x coordinate, give the matching character index
// Tool fct : From a word and a x coordinate (font scale), give the matching character index
static uint getCharacterIndex(const ucstring &textValue, float x, NL3D::UTextContext &textContext)
{
float px = 0.f;
UTextContext::CStringInfo si;
ucstring singleChar(" ");
uint i;
@ -2349,7 +2399,7 @@ namespace NLGUI
if (px > x)
{
// if the half of the character is after the cursor, then prefer select the next one (like in Word)
if(px-si.StringWidth/2 < x)
if(px-si.StringWidth/2.f < x)
i++;
break;
}
@ -2358,15 +2408,18 @@ namespace NLGUI
}
// ***************************************************************************
void CViewText::getCharacterIndexFromPosition(sint x, sint y, uint &index, bool &cursorAtPreviousLineEnd) const
void CViewText::getCharacterIndexFromPosition(float x, float y, uint &index, bool &cursorAtPreviousLineEnd) const
{
NL3D::UTextContext *TextContext = CViewRenderer::getTextContext(_FontName);
x *= _Scale;
y = roundf(y * _Scale);
// setup the text context
TextContext->setHotSpot (UTextContext::BottomLeft);
TextContext->setShaded (_Shadow);
TextContext->setShadeOutline (_ShadowOutline);
TextContext->setFontSize (_FontSize);
TextContext->setFontSize (_FontSize*_Scale);
TextContext->setEmbolden (_Embolden);
TextContext->setOblique (_Oblique);
// find the line where the character is
@ -2374,7 +2427,7 @@ namespace NLGUI
uint charPos = 0;
if (_MultiLine)
{
y -= getMultiMinOffsetY();
y -= getMultiMinOffsetY() * _Scale;
// seek the line
float py = 0.f;
if (py > y)
@ -2386,7 +2439,7 @@ namespace NLGUI
sint line;
for (line = (uint)_Lines.size() - 1; line >= 0; --line)
{
float newPy = py + _FontHeight + _MultiLineSpace;
float newPy = py + _FontHeight + _MultiLineSpace * _Scale;
if (newPy > y)
{
break;
@ -2419,6 +2472,7 @@ namespace NLGUI
return;
}
cursorAtPreviousLineEnd = false;
float px = (float)_FirstLineX;
for(uint k = 0; k < currLine.getNumWords(); ++k)
{
@ -2435,14 +2489,12 @@ namespace NLGUI
: 0;
clamp(numSpaces, 0, (sint)currWord.NumSpaces);
index = numSpaces + charPos;
cursorAtPreviousLineEnd = false;
return;
}
else
{
// the coord is in the word itself
index = charPos + currWord.NumSpaces + getCharacterIndex(currWord.Text, (float) x - (px + spacesWidth), *TextContext);
cursorAtPreviousLineEnd = false;
index = charPos + currWord.NumSpaces + getCharacterIndex(currWord.Text, x - (px + spacesWidth), *TextContext);
return;
}
}
@ -2450,7 +2502,6 @@ namespace NLGUI
charPos += (uint)currWord.Text.length() + currWord.NumSpaces;
}
index = charPos;
cursorAtPreviousLineEnd = false;
return;
}
else
@ -2466,7 +2517,7 @@ namespace NLGUI
index = 0;
return;
}
index = getCharacterIndex(_Text, (float) x, *TextContext);
index = getCharacterIndex(_Text, x, *TextContext);
return;
}
}
@ -2534,21 +2585,21 @@ namespace NLGUI
// ***************************************************************************
uint CViewText::getFirstLineX() const
{
return _FirstLineX;
return _FirstLineX / _Scale;
}
// ***************************************************************************
uint CViewText::getLastLineW () const
{
if (!_Lines.empty())
return (uint)_Lines.back()->getWidth();
return (uint)_Lines.back()->getWidth() / _Scale;
return 0;
}
// ***************************************************************************
void CViewText::setFirstLineX(sint firstLineX)
{
_FirstLineX = firstLineX;
_FirstLineX = firstLineX * _Scale;
}
/////////////////////////////////////
@ -2567,7 +2618,7 @@ namespace NLGUI
}
// ***************************************************************************
void CViewText::CLine::addWord(const ucstring &text, uint numSpaces, const CFormatInfo &wordFormat, uint fontWidth, NL3D::UTextContext &textContext)
void CViewText::CLine::addWord(const ucstring &text, uint numSpaces, const CFormatInfo &wordFormat, float fontWidth, NL3D::UTextContext &textContext)
{
CWord word;
word.build(text, textContext, numSpaces);
@ -2576,7 +2627,7 @@ namespace NLGUI
}
// ***************************************************************************
void CViewText::CLine::addWord(const CWord &word, uint fontWidth)
void CViewText::CLine::addWord(const CWord &word, float fontWidth)
{
_Words.push_back(word);
_NumChars += word.NumSpaces + uint(word.Text.length());
@ -2586,7 +2637,7 @@ namespace NLGUI
_StringLine = word.Info.StringLine;
}
// the width of the line must reach at least the Tab
_WidthWithoutSpaces= max(_WidthWithoutSpaces, word.Format.TabX * float(fontWidth));
_WidthWithoutSpaces= max(_WidthWithoutSpaces, word.Format.TabX * fontWidth);
// append the text space
_WidthWithoutSpaces += word.Info.StringWidth;
}
@ -2644,7 +2695,7 @@ namespace NLGUI
TextContext->setHotSpot (UTextContext::BottomLeft);
TextContext->setShaded (_Shadow);
TextContext->setShadeOutline (_ShadowOutline);
TextContext->setFontSize (_FontSize);
TextContext->setFontSize (_FontSize*_Scale);
TextContext->setEmbolden (_Embolden);
TextContext->setOblique (_Oblique);
@ -2705,14 +2756,14 @@ namespace NLGUI
linePos = lineEnd+1;
}
return (sint32)maxWidth;
return (sint32)ceilf(maxWidth / _Scale);
}
// ***************************************************************************
sint32 CViewText::getMinUsedW() const
{
static const ucstring spaceOrLineFeedStr(" \n\t");
sint32 maxWidth = 0;
float maxWidth = 0.0f;
// Not multi line ? Same size than min
if (!_MultiLine)
@ -2722,7 +2773,7 @@ namespace NLGUI
if (_TextMode == ClipWord)
{
// No largest font parameter, return the font height
return _FontHeight;
return (sint32)ceilf(_FontHeight / _Scale);
}
// If we can't clip the words, return the size of the largest word
else if ((_TextMode == DontClipWord) || (_TextMode == Justified))
@ -2731,7 +2782,7 @@ namespace NLGUI
TextContext->setHotSpot (UTextContext::BottomLeft);
TextContext->setShaded (_Shadow);
TextContext->setShadeOutline (_ShadowOutline);
TextContext->setFontSize (_FontSize);
TextContext->setFontSize (_FontSize*_Scale);
TextContext->setEmbolden (_Embolden);
TextContext->setOblique (_Oblique);
@ -2759,16 +2810,15 @@ namespace NLGUI
si = TextContext->getStringInfo(wordValue);
// Larger ?
sint32 stringWidth = (sint32)si.StringWidth;
if (stringWidth>maxWidth)
maxWidth = stringWidth;
if (maxWidth < si.StringWidth)
maxWidth = si.StringWidth;
// Next word
currPos = wordEnd;
}
}
return maxWidth;
return ceilf(maxWidth / _Scale);
}
// ***************************************************************************
@ -2782,6 +2832,17 @@ namespace NLGUI
invalidateCoords();
}
// ***************************************************************************
void CViewText::onInterfaceScaleChanged()
{
_Scale = CWidgetManager::getInstance()->getInterfaceScale();
computeFontSize ();
invalidateContent();
CViewBase::onInterfaceScaleChanged();
}
// ***************************************************************************
void CViewText::computeFontSize ()
{
@ -2789,7 +2850,7 @@ namespace NLGUI
TextContext->setHotSpot (UTextContext::BottomLeft);
TextContext->setShaded (_Shadow);
TextContext->setShadeOutline (_ShadowOutline);
TextContext->setFontSize (_FontSize);
TextContext->setFontSize (_FontSize * _Scale);
TextContext->setEmbolden (_Embolden);
TextContext->setOblique (_Oblique);
@ -2811,8 +2872,8 @@ namespace NLGUI
si = TextContext->getStringInfo(chars);
}
// add a padding of 1 pixel else the top will be truncated
_FontHeight = (uint) si.StringHeight+1;
_FontLegHeight = (uint) si.StringLine;
_FontHeight = si.StringHeight + 1;
_FontLegHeight = si.StringLine;
// Space width
si = TextContext->getStringInfo(ucstring(" "));
@ -2820,7 +2881,7 @@ namespace NLGUI
// Font Width
si = TextContext->getStringInfo(ucstring("_"));
_FontWidth = (uint)si.StringWidth;
_FontWidth = si.StringWidth;
}

View file

@ -1893,6 +1893,13 @@ namespace NLGUI
}
CViewRenderer::getInstance()->setClipWindow(0, 0, w, h);
bool scaleChanged = _InterfaceScale != CViewRenderer::getInstance()->getInterfaceScale();
if (scaleChanged)
{
_InterfaceScale = CViewRenderer::getInstance()->getInterfaceScale();
notifyInterfaceScaleWatchers();
}
// If all conditions are OK, move windows so they fit correctly with new screen size
// Do this work only InGame when Config is loaded
moveAllWindowsToNewScreenSize(w,h,true);
@ -3688,6 +3695,42 @@ namespace NLGUI
}
// ------------------------------------------------------------------------------------------------
void CWidgetManager::notifyInterfaceScaleWatchers()
{
std::vector< IInterfaceScaleWatcher* >::iterator itr = scaleWatchers.begin();
while( itr != scaleWatchers.end() )
{
(*itr)->onInterfaceScaleChanged();
++itr;
}
}
// ------------------------------------------------------------------------------------------------
void CWidgetManager::registerInterfaceScaleWatcher( IInterfaceScaleWatcher *watcher )
{
std::vector< IInterfaceScaleWatcher* >::const_iterator itr
= std::find( scaleWatchers.begin(), scaleWatchers.end(), watcher );
if( itr != scaleWatchers.end() )
return;
scaleWatchers.push_back( watcher );
}
// ------------------------------------------------------------------------------------------------
void CWidgetManager::unregisterInterfaceScaleWatcher( IInterfaceScaleWatcher *watcher )
{
std::vector< IInterfaceScaleWatcher* >::iterator itr
= std::find( scaleWatchers.begin(), scaleWatchers.end(), watcher );
if( itr == scaleWatchers.end() )
return;
scaleWatchers.erase( itr );
}
// ------------------------------------------------------------------------------------------------
CWidgetManager::CWidgetManager()
{
LinkHack();
@ -3724,6 +3767,7 @@ namespace NLGUI
inGame = false;
setScreenWH(0, 0);
_InterfaceScale = 1.0f;
_GroupSelection = false;
multiSelection = false;

View file

@ -214,6 +214,7 @@ int main(int argc, char **argv)
args.addArg("x", "extract", "", "Extract all interface elements from <output_filename> to <input_path>.");
args.addAdditionalArg("output_filename", "PNG or TGA file to generate", true);
args.addAdditionalArg("input_path", "Path that containts interfaces elements", false);
args.addArg("b", "border", "", "Duplicate icon border to allow bilinear filtering");
if (!args.parse(argc, argv)) return 1;
@ -227,6 +228,13 @@ int main(int argc, char **argv)
existingUVfilename = args.getArg("s").front();
}
//
uint borderSize = 0;
if (args.haveArg("b"))
{
borderSize = 1;
}
// extract all interface elements
bool extractElements = args.haveArg("x");
@ -407,6 +415,18 @@ int main(int argc, char **argv)
pBtmp->convertToType(CBitmap::RGBA);
}
// duplicate icon border
if (borderSize > 0)
{
NLMISC::CBitmap *tmp = new NLMISC::CBitmap;
tmp->resize(pBtmp->getWidth(), pBtmp->getHeight());
tmp->blit(pBtmp, 0, 0);
tmp->resample(tmp->getWidth() + borderSize * 2, tmp->getHeight() + borderSize * 2);
tmp->blit(pBtmp, borderSize, borderSize);
delete pBtmp;
pBtmp = tmp;
}
AllMaps[i] = pBtmp;
}
catch (const NLMISC::Exception &e)
@ -461,10 +481,10 @@ int main(int argc, char **argv)
putIn (AllMaps[i], &GlobalTexture, x, y);
putIn (AllMaps[i], &GlobalMask, x, y, false);
UVMin[i].U = (float)x;
UVMin[i].V = (float)y;
UVMax[i].U = (float)x+AllMaps[i]->getWidth();
UVMax[i].V = (float)y+AllMaps[i]->getHeight();
UVMin[i].U = (float)x + borderSize;
UVMin[i].V = (float)y + borderSize;
UVMax[i].U = (float)x + AllMaps[i]->getWidth() - borderSize;
UVMax[i].V = (float)y + AllMaps[i]->getHeight() - borderSize;
#if 0
// Do not remove this is useful for debugging

View file

@ -122,6 +122,8 @@
<command name="loot" action="inv_temp_all" params="" />
<command name="setuiscale" action="set_ui_scale" params="scale=$"/>
<command name="mapsearch" action="proc" params="map_search_show_set|+" />
<command name="mapsearch" action="proc" params="map_search_show" />

View file

@ -300,6 +300,9 @@ CClientConfig::CClientConfig()
Luminosity = 0.f; // Default Monitor Luminosity.
Gamma = 0.f; // Default Monitor Gamma.
InterfaceScale = 1.0f; // Resize UI
BilinearUI = false;
VREnable = false;
VRDisplayDevice = "Auto";
VRDisplayDeviceId = "";
@ -838,6 +841,10 @@ void CClientConfig::setValues()
READ_FLOAT_FV(Luminosity)
// Gamma
READ_FLOAT_FV(Gamma)
// UI scaling
READ_FLOAT_FV(InterfaceScale);
clamp(ClientCfg.InterfaceScale, MIN_INTERFACE_SCALE, MAX_INTERFACE_SCALE);
READ_BOOL_FV(BilinearUI);
// 3D Driver
varPtr = ClientCfg.ConfigFile.getVarPtr ("Driver3D");
if (varPtr)

View file

@ -46,6 +46,9 @@ using NLMISC::CVector;
using NLMISC::CRGBA;
using std::string;
// limits for UI scale
const float MIN_INTERFACE_SCALE = 0.8;
const float MAX_INTERFACE_SCALE = 2.0;
//---------------------------------------------------
// CClientConfig :
@ -146,6 +149,10 @@ struct CClientConfig
/// Monitor Gamma [-1 ~ 1], default 0
float Gamma;
// UI scaling
float InterfaceScale;
bool BilinearUI;
// VR
bool VREnable;
std::string VRDisplayDevice;

View file

@ -227,6 +227,9 @@ void connectionRestoreVideoMode ()
SetMouseCursor ();
SetMouseSpeed (ClientCfg.CursorSpeed);
SetMouseAcceleration (ClientCfg.CursorAcceleration);
// Restore user UI scaling
CViewRenderer::getInstance()->setInterfaceScale(ClientCfg.InterfaceScale);
}
@ -262,6 +265,8 @@ void setOutGameFullScreen()
InitMouseWithCursor(ClientCfg.HardwareCursor && !StereoDisplayAttached);
}
// Enable auto scaling in login window
CViewRenderer::getInstance()->setInterfaceScale(1.0f, 1024, 768);
}
@ -427,6 +432,9 @@ bool connection (const string &cookie, const string &fsaddr)
firstConnection = false;
// Restore user UI scaling
CViewRenderer::getInstance()->setInterfaceScale(ClientCfg.InterfaceScale);
// Disable inputs
Actions.enable(false);
EditActions.enable(false);
@ -558,6 +566,9 @@ bool reconnection()
InterfaceState = globalMenu();
}
// Restore user UI scaling
CViewRenderer::getInstance()->setInterfaceScale(ClientCfg.InterfaceScale);
// Disable inputs
Actions.enable(false);
EditActions.enable(false);

View file

@ -1332,6 +1332,8 @@ void prelogInit()
CInterfaceManager::getInstance();
CViewRenderer::getInstance()->setInterfaceScale(1.0f, 1024, 768);
CViewRenderer::getInstance()->setBilinearFiltering(ClientCfg.BilinearUI);
// Yoyo: initialize NOW the InputHandler for Event filtering.
CInputHandlerManager *InputHandlerManager = CInputHandlerManager::getInstance();

View file

@ -179,9 +179,9 @@ void SetMouseCursor (bool updatePos)
// Get the last cursor
float x = 0.5f, y = 0.5f;
// Window size
uint width = Driver->getWindowWidth();
uint height = Driver->getWindowHeight();
// Screen size
uint width, height;
CViewRenderer::getInstance()->getScreenSize(width, height);
// Update the interface pointer
CInterfaceManager *instance = CInterfaceManager::getInstance();

View file

@ -383,10 +383,10 @@ class CAHEditPreviousLine : public CAHEdit
// .. so do nothing
return;
}
sint cx, cy;
sint height;
float cx, cy;
float height;
_GroupEdit->getViewText()->getCharacterPositionFromIndex(cursorPosInText, _GroupEdit->isCursorAtPreviousLineEnd(), cx, cy, height);
cy += height + _GroupEdit->getViewText()->getMultiLineSpace();
cy += _GroupEdit->getViewText()->getLineHeight();
uint newCharIndex;
bool newLineEnd;
_GroupEdit->getViewText()->getCharacterIndexFromPosition(cx, cy, newCharIndex, newLineEnd);
@ -401,8 +401,8 @@ class CAHEditPreviousLine : public CAHEdit
}
_GroupEdit->setCursorAtPreviousLineEnd(false);
// takes character whose X is closer to the current X
sint cx0, cx1;
sint cy0, cy1;
float cx0, cx1;
float cy0, cy1;
_GroupEdit->getViewText()->getCharacterPositionFromIndex(newCharIndex, _GroupEdit->isCursorAtPreviousLineEnd(), cx0, cy0, height);
_GroupEdit->getViewText()->getCharacterPositionFromIndex(newCharIndex + 1, _GroupEdit->isCursorAtPreviousLineEnd(), cx1, cy1, height);
if (abs(cx0 - cx) < abs(cx1 - cx) || cy0 != cy1)
@ -446,8 +446,8 @@ class CAHEditNextLine : public CAHEdit
}
else if (_GroupEdit->getViewText()->getMultiLine())
{
sint cx, cy;
sint height;
float cx, cy;
float height;
_GroupEdit->getViewText()->getCharacterPositionFromIndex(_GroupEdit->getCursorPos() + (sint)_GroupEdit->getPrompt().length(), _GroupEdit->isCursorAtPreviousLineEnd(), cx, cy, height);
if (cy != 0)
{
@ -466,8 +466,8 @@ class CAHEditNextLine : public CAHEdit
}
_GroupEdit->setCursorAtPreviousLineEnd(false);
// takes character whose X is closer to the current X
sint cx0, cx1;
sint cy0, cy1;
float cx0, cx1;
float cy0, cy1;
_GroupEdit->getViewText()->getCharacterPositionFromIndex(newCharIndex, _GroupEdit->isCursorAtPreviousLineEnd(), cx0, cy0, height);
_GroupEdit->getViewText()->getCharacterPositionFromIndex(newCharIndex + 1, _GroupEdit->isCursorAtPreviousLineEnd(), cx1, cy1, height);
if (abs(cx0 - cx) < abs(cx1 - cx) || cy0 != cy1)

View file

@ -3732,6 +3732,34 @@ class CHandlerGameConfigChangeScreenRatioCustom : public IActionHandler
};
REGISTER_ACTION_HANDLER (CHandlerGameConfigChangeScreenRatioCustom, "game_config_change_screen_ratio_custom");
// ***************************************************************************
class CHandlerSetInterfaceScale : public IActionHandler
{
virtual void execute (CCtrlBase *pCaller, const string &Params)
{
std::string s;
s = getParam(Params, "scale");
if (!s.empty()) {
float scale;
if (fromString(s, scale))
{
if (scale >= MIN_INTERFACE_SCALE && scale <= MAX_INTERFACE_SCALE)
{
ClientCfg.InterfaceScale = scale;
ClientCfg.writeDouble("InterfaceScale", ClientCfg.InterfaceScale);
ClientCfg.IsInvalidated = true;
return;
}
}
}
ucstring help("/setuiscale "+toString("%.1f .. %.1f", MIN_INTERFACE_SCALE, MAX_INTERFACE_SCALE));
CInterfaceManager::getInstance()->displaySystemInfo(help);
}
};
REGISTER_ACTION_HANDLER (CHandlerSetInterfaceScale, "set_ui_scale");
// ***************************************************************************
class CHandlerGameMissionAbandon : public IActionHandler

View file

@ -86,8 +86,10 @@ void CGroupInScene::computeWindowPos(sint32 &newX, sint32 &newY, CVector &newPro
tmp = pVR.getFrustum().projectZ (tmp);
// Get the width and height
tmp.x *= (float)CViewRenderer::getInstance()->getDriver()->getWindowWidth();
tmp.y *= (float)CViewRenderer::getInstance()->getDriver()->getWindowHeight();
uint32 width, height;
CViewRenderer::getInstance()->getScreenSize(width, height);
tmp.x *= width;
tmp.y *= height;
// position without offset, in float
newProjCenter.x= tmp.x;

View file

@ -680,9 +680,8 @@ CGroupInSceneBubbleManager::CPopupContext *CGroupInSceneBubbleManager::buildCont
if (target)
{
// Find a position
NL3D::UDriver *Driver = CViewRenderer::getInstance()->getDriver();
const uint width = Driver->getWindowWidth();
const uint height = Driver->getWindowHeight();
uint32 width, height;
CViewRenderer::getInstance()->getScreenSize(width, height);
h = (target->getXReal() < ((sint)width-target->getXReal()-target->getWReal()))?"l":"r";
v = (target->getYReal() < ((sint)height-target->getYReal()-target->getHReal()))?"b":"t";
target->setActive(true);

View file

@ -484,6 +484,8 @@ CInterfaceManager::CInterfaceManager()
interfaceLinkUpdater = new CInterfaceLink::CInterfaceLinkUpdater();
_ScreenW = _ScreenH = 0;
_LastInGameScreenW = _LastInGameScreenH = 0;
_InterfaceScaleChanged = false;
_InterfaceScale = 1.0f;
_DescTextTarget = NULL;
_ConfigLoaded = false;
_LogState = false;
@ -1828,8 +1830,12 @@ bool CInterfaceManager::loadConfig (const string &filename)
CWidgetManager::getInstance()->setScreenWH(_LastInGameScreenW, _LastInGameScreenH);
// NB: we are typically InGame here (even though the _InGame flag is not yet set)
// Use the screen size of the config file. Don't update current UI, just _Modes
CWidgetManager::getInstance()->moveAllWindowsToNewScreenSize(ClientCfg.Width, ClientCfg.Height, false);
updateDesktops( ClientCfg.Width, ClientCfg.Height );
//
// ClientCfg has W/H set to screen size, but interface expects scaled size
sint32 scaledW = ClientCfg.Width / ClientCfg.InterfaceScale;
sint32 scaledH = ClientCfg.Height / ClientCfg.InterfaceScale;
CWidgetManager::getInstance()->moveAllWindowsToNewScreenSize(scaledW, scaledH, false);
updateDesktops(scaledW, scaledH);
}
// *** apply the current mode
@ -2050,6 +2056,13 @@ void CInterfaceManager::drawViews(NL3D::UCamera camera)
_CurrentPlayerCharac[i] = node ? node->getValue32() : 0;
}
// scale must be updated right before widget manager checks it
if (_InterfaceScaleChanged)
{
CViewRenderer::getInstance()->setInterfaceScale(_InterfaceScale);
_InterfaceScaleChanged = false;
}
CWidgetManager::getInstance()->drawViews( camera );
// flush obs
@ -2938,7 +2951,6 @@ NLMISC_COMMAND(loadui, "Load an interface file", "<loadui [all]/interface.xml>")
return result;
}
// ***************************************************************************
void CInterfaceManager::displayWebWindow(const string & name, const string & url)
{

View file

@ -549,6 +549,7 @@ public:
NLMISC::CCDBNodeLeaf *_DB_UI_DUMMY_FACTION_TYPE;
void updateDesktops( uint32 newScreenW, uint32 newScreenH );
void setInterfaceScale( float scale ) { _InterfaceScaleChanged = true; _InterfaceScale = scale; }
private:
@ -587,6 +588,8 @@ private:
uint32 _ScreenW, _ScreenH; // Change res detection
sint32 _LastInGameScreenW, _LastInGameScreenH; // Resolution used for last InGame interface
float _InterfaceScale;
bool _InterfaceScaleChanged;
// Modes
std::vector<CInterfaceConfig::CDesktopImage> _Modes;

View file

@ -36,6 +36,7 @@
#include "input.h"
#include "sound_manager.h"
#include "camera.h"
#include "interface_v3/interface_manager.h"
using namespace NLMISC;
using namespace NL3D;
@ -100,6 +101,12 @@ void updateFromClientCfg()
Driver->forceTextureResize(1);
}
if (ClientCfg.InterfaceScale != LastClientCfg.InterfaceScale)
CInterfaceManager::getInstance()->setInterfaceScale(ClientCfg.InterfaceScale);
if (ClientCfg.BilinearUI != LastClientCfg.BilinearUI)
CViewRenderer::getInstance()->setBilinearFiltering(ClientCfg.BilinearUI);
//---------------------------------------------------
if (ClientCfg.WaitVBL != LastClientCfg.WaitVBL)
{