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

View file

@ -176,6 +176,13 @@ namespace NLGUI
*/ */
void getScreenOOSize (float &oow, float &ooh); 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? * is the Screen minimized?
*/ */
@ -185,7 +192,7 @@ namespace NLGUI
* drawBitmap : this is the interface with all the views * 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)); sint32 nTxId, const NLMISC::CRGBA &col = NLMISC::CRGBA(255,255,255,255));
/* /*
@ -526,6 +533,14 @@ namespace NLGUI
float _OneOverScreenW, _OneOverScreenH; float _OneOverScreenW, _OneOverScreenH;
bool _IsMinimized; 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 //map linking a uint to a bitmap. Used to display figurs
std::vector<sint32> _IndexesToTextureIds; std::vector<sint32> _IndexesToTextureIds;
@ -596,7 +611,6 @@ namespace NLGUI
/// Set of hw cursor images /// Set of hw cursor images
static std::set< std::string > *hwCursors; static std::set< std::string > *hwCursors;
static float hwCursorScale; static float hwCursorScale;
}; };

View file

@ -70,6 +70,7 @@ namespace NLGUI
virtual void checkCoords(); virtual void checkCoords();
virtual void updateCoords(); virtual void updateCoords();
virtual void onAddToGroup(); virtual void onAddToGroup();
virtual void onInterfaceScaleChanged();
/// From CInterfaceElement /// From CInterfaceElement
sint32 getMaxUsedW() const; sint32 getMaxUsedW() const;
@ -90,6 +91,7 @@ namespace NLGUI
void setShadowColor (const NLMISC::CRGBA &color); void setShadowColor (const NLMISC::CRGBA &color);
void setShadowOffset (sint x, sint y); void setShadowOffset (sint x, sint y);
void setLineMaxW (sint nMaxW, bool invalidate=true); void setLineMaxW (sint nMaxW, bool invalidate=true);
void setOverflowText(const ucstring &text) { _OverflowText = text; }
void setMultiLine (bool bMultiLine); void setMultiLine (bool bMultiLine);
void setMultiLineSpace (sint nMultiLineSpace); void setMultiLineSpace (sint nMultiLineSpace);
void setMultiLineMaxWOnly (bool state); void setMultiLineMaxWOnly (bool state);
@ -115,6 +117,7 @@ namespace NLGUI
NLMISC::CRGBA getShadowColor() { return _ShadowColor; } NLMISC::CRGBA getShadowColor() { return _ShadowColor; }
void getShadowOffset(sint &x, sint &y) { x = _ShadowX; y = _ShadowY; } void getShadowOffset(sint &x, sint &y) { x = _ShadowX; y = _ShadowY; }
sint getLineMaxW() const { return _LineMaxW; } sint getLineMaxW() const { return _LineMaxW; }
ucstring getOverflowText() const { return _OverflowText; }
bool getMultiLine() const { return _MultiLine; } bool getMultiLine() const { return _MultiLine; }
sint getMultiLineSpace() const { return _MultiLineSpace; } sint getMultiLineSpace() const { return _MultiLineSpace; }
bool getMultiLineMaxWOnly() const { return _MultiLineMaxWOnly; } bool getMultiLineMaxWOnly() const { return _MultiLineMaxWOnly; }
@ -128,6 +131,8 @@ namespace NLGUI
uint getFontHeight() const; uint getFontHeight() const;
// get current font leg height, in pixels // get current font leg height, in pixels
uint getFontLegHeight() const; uint getFontLegHeight() const;
// get current line height, in pixels
float getLineHeight() const;
// Set the display mode (supported with multiline only for now) // Set the display mode (supported with multiline only for now)
void setTextMode(TTextMode mode); void setTextMode(TTextMode mode);
TTextMode getTextMode() const { return _TextMode; } 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 * 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 * 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. /** 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) * 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 /** 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 * \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 _Embolden;
bool _Oblique; bool _Oblique;
// width of the font in pixel. Just a Hint for tabing format (computed with '_') // width of the font in pixel. Just a Hint for tabing format (computed with '_')
uint _FontWidth; float _FontWidth;
// height of the font in pixel. // height of the font in pixel.
// use getFontHeight // use getFontHeight
uint _FontHeight; float _FontHeight;
uint _FontLegHeight; float _FontLegHeight;
float _SpaceWidth; float _SpaceWidth;
/// last UI scale used to calculate font size
float _Scale;
/// the text color /// the text color
NLMISC::CRGBA _Color; NLMISC::CRGBA _Color;
/// the shadow mode /// the shadow mode
@ -260,6 +267,7 @@ namespace NLGUI
sint32 _LineMaxW; sint32 _LineMaxW;
/// For single line, true if the text is clamped (ie displayed with "...") /// For single line, true if the text is clamped (ie displayed with "...")
bool _SingleLineTextClamped; bool _SingleLineTextClamped;
ucstring _OverflowText;
/// Multiple lines handling /// Multiple lines handling
bool _MultiLine; bool _MultiLine;
@ -341,8 +349,8 @@ namespace NLGUI
// Clear the line & remove text contexts // Clear the line & remove text contexts
void clear(NL3D::UTextContext &textContext); 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 // 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 ucstring &word, uint numSpaces, const CFormatInfo &wordFormat, float fontWidth, NL3D::UTextContext &textContext);
void addWord(const CWord &word, uint fontWidth); void addWord(const CWord &word, float fontWidth);
uint getNumWords() const { return (uint)_Words.size(); } uint getNumWords() const { return (uint)_Words.size(); }
CWord &getWord(uint index) { return _Words[index]; } CWord &getWord(uint index) { return _Words[index]; }
float getSpaceWidth() const { return _SpaceWidth; } float getSpaceWidth() const { return _SpaceWidth; }
@ -402,7 +410,7 @@ namespace NLGUI
uint _TextSelectionEnd; uint _TextSelectionEnd;
// First line X coordinate // First line X coordinate
sint _FirstLineX; float _FirstLineX;
/// Dynamic tooltips /// Dynamic tooltips
std::vector<CCtrlToolTip*> _Tooltips; std::vector<CCtrlToolTip*> _Tooltips;

View file

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

View file

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

View file

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

View file

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

View file

@ -1850,7 +1850,7 @@ namespace NLGUI
class InvalidateTextVisitor : public CInterfaceElementVisitor class InvalidateTextVisitor : public CInterfaceElementVisitor
{ {
public: public:
InvalidateTextVisitor( bool reset ) InvalidateTextVisitor( bool reset)
{ {
this->reset = reset; this->reset = reset;
} }
@ -1893,6 +1893,13 @@ namespace NLGUI
} }
CViewRenderer::getInstance()->setClipWindow(0, 0, w, h); 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 // If all conditions are OK, move windows so they fit correctly with new screen size
// Do this work only InGame when Config is loaded // Do this work only InGame when Config is loaded
moveAllWindowsToNewScreenSize(w,h,true); moveAllWindowsToNewScreenSize(w,h,true);
@ -1902,7 +1909,7 @@ namespace NLGUI
{ {
SMasterGroup &rMG = _MasterGroups[nMasterGroup]; SMasterGroup &rMG = _MasterGroups[nMasterGroup];
InvalidateTextVisitor inv( false ); InvalidateTextVisitor inv( false);
rMG.Group->visitGroupAndChildren( &inv ); rMG.Group->visitGroupAndChildren( &inv );
rMG.Group->invalidateCoords (); rMG.Group->invalidateCoords ();
@ -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() CWidgetManager::CWidgetManager()
{ {
LinkHack(); LinkHack();
@ -3724,6 +3767,7 @@ namespace NLGUI
inGame = false; inGame = false;
setScreenWH(0, 0); setScreenWH(0, 0);
_InterfaceScale = 1.0f;
_GroupSelection = false; _GroupSelection = false;
multiSelection = 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.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("output_filename", "PNG or TGA file to generate", true);
args.addAdditionalArg("input_path", "Path that containts interfaces elements", false); 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; if (!args.parse(argc, argv)) return 1;
@ -227,6 +228,13 @@ int main(int argc, char **argv)
existingUVfilename = args.getArg("s").front(); existingUVfilename = args.getArg("s").front();
} }
//
uint borderSize = 0;
if (args.haveArg("b"))
{
borderSize = 1;
}
// extract all interface elements // extract all interface elements
bool extractElements = args.haveArg("x"); bool extractElements = args.haveArg("x");
@ -407,6 +415,18 @@ int main(int argc, char **argv)
pBtmp->convertToType(CBitmap::RGBA); 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; AllMaps[i] = pBtmp;
} }
catch (const NLMISC::Exception &e) catch (const NLMISC::Exception &e)
@ -461,10 +481,10 @@ int main(int argc, char **argv)
putIn (AllMaps[i], &GlobalTexture, x, y); putIn (AllMaps[i], &GlobalTexture, x, y);
putIn (AllMaps[i], &GlobalMask, x, y, false); putIn (AllMaps[i], &GlobalMask, x, y, false);
UVMin[i].U = (float)x; UVMin[i].U = (float)x + borderSize;
UVMin[i].V = (float)y; UVMin[i].V = (float)y + borderSize;
UVMax[i].U = (float)x+AllMaps[i]->getWidth(); UVMax[i].U = (float)x + AllMaps[i]->getWidth() - borderSize;
UVMax[i].V = (float)y+AllMaps[i]->getHeight(); UVMax[i].V = (float)y + AllMaps[i]->getHeight() - borderSize;
#if 0 #if 0
// Do not remove this is useful for debugging // Do not remove this is useful for debugging

View file

@ -122,6 +122,8 @@
<command name="loot" action="inv_temp_all" params="" /> <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_set|+" />
<command name="mapsearch" action="proc" params="map_search_show" /> <command name="mapsearch" action="proc" params="map_search_show" />

View file

@ -300,6 +300,9 @@ CClientConfig::CClientConfig()
Luminosity = 0.f; // Default Monitor Luminosity. Luminosity = 0.f; // Default Monitor Luminosity.
Gamma = 0.f; // Default Monitor Gamma. Gamma = 0.f; // Default Monitor Gamma.
InterfaceScale = 1.0f; // Resize UI
BilinearUI = false;
VREnable = false; VREnable = false;
VRDisplayDevice = "Auto"; VRDisplayDevice = "Auto";
VRDisplayDeviceId = ""; VRDisplayDeviceId = "";
@ -838,6 +841,10 @@ void CClientConfig::setValues()
READ_FLOAT_FV(Luminosity) READ_FLOAT_FV(Luminosity)
// Gamma // Gamma
READ_FLOAT_FV(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 // 3D Driver
varPtr = ClientCfg.ConfigFile.getVarPtr ("Driver3D"); varPtr = ClientCfg.ConfigFile.getVarPtr ("Driver3D");
if (varPtr) if (varPtr)

View file

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

View file

@ -227,6 +227,9 @@ void connectionRestoreVideoMode ()
SetMouseCursor (); SetMouseCursor ();
SetMouseSpeed (ClientCfg.CursorSpeed); SetMouseSpeed (ClientCfg.CursorSpeed);
SetMouseAcceleration (ClientCfg.CursorAcceleration); SetMouseAcceleration (ClientCfg.CursorAcceleration);
// Restore user UI scaling
CViewRenderer::getInstance()->setInterfaceScale(ClientCfg.InterfaceScale);
} }
@ -262,6 +265,8 @@ void setOutGameFullScreen()
InitMouseWithCursor(ClientCfg.HardwareCursor && !StereoDisplayAttached); 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; firstConnection = false;
// Restore user UI scaling
CViewRenderer::getInstance()->setInterfaceScale(ClientCfg.InterfaceScale);
// Disable inputs // Disable inputs
Actions.enable(false); Actions.enable(false);
EditActions.enable(false); EditActions.enable(false);
@ -558,6 +566,9 @@ bool reconnection()
InterfaceState = globalMenu(); InterfaceState = globalMenu();
} }
// Restore user UI scaling
CViewRenderer::getInstance()->setInterfaceScale(ClientCfg.InterfaceScale);
// Disable inputs // Disable inputs
Actions.enable(false); Actions.enable(false);
EditActions.enable(false); EditActions.enable(false);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -484,6 +484,8 @@ CInterfaceManager::CInterfaceManager()
interfaceLinkUpdater = new CInterfaceLink::CInterfaceLinkUpdater(); interfaceLinkUpdater = new CInterfaceLink::CInterfaceLinkUpdater();
_ScreenW = _ScreenH = 0; _ScreenW = _ScreenH = 0;
_LastInGameScreenW = _LastInGameScreenH = 0; _LastInGameScreenW = _LastInGameScreenH = 0;
_InterfaceScaleChanged = false;
_InterfaceScale = 1.0f;
_DescTextTarget = NULL; _DescTextTarget = NULL;
_ConfigLoaded = false; _ConfigLoaded = false;
_LogState = false; _LogState = false;
@ -1828,8 +1830,12 @@ bool CInterfaceManager::loadConfig (const string &filename)
CWidgetManager::getInstance()->setScreenWH(_LastInGameScreenW, _LastInGameScreenH); CWidgetManager::getInstance()->setScreenWH(_LastInGameScreenW, _LastInGameScreenH);
// NB: we are typically InGame here (even though the _InGame flag is not yet set) // 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 // 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 // *** apply the current mode
@ -2050,6 +2056,13 @@ void CInterfaceManager::drawViews(NL3D::UCamera camera)
_CurrentPlayerCharac[i] = node ? node->getValue32() : 0; _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 ); CWidgetManager::getInstance()->drawViews( camera );
// flush obs // flush obs
@ -2938,7 +2951,6 @@ NLMISC_COMMAND(loadui, "Load an interface file", "<loadui [all]/interface.xml>")
return result; return result;
} }
// *************************************************************************** // ***************************************************************************
void CInterfaceManager::displayWebWindow(const string & name, const string & url) void CInterfaceManager::displayWebWindow(const string & name, const string & url)
{ {

View file

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

View file

@ -36,6 +36,7 @@
#include "input.h" #include "input.h"
#include "sound_manager.h" #include "sound_manager.h"
#include "camera.h" #include "camera.h"
#include "interface_v3/interface_manager.h"
using namespace NLMISC; using namespace NLMISC;
using namespace NL3D; using namespace NL3D;
@ -100,6 +101,12 @@ void updateFromClientCfg()
Driver->forceTextureResize(1); 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) if (ClientCfg.WaitVBL != LastClientCfg.WaitVBL)
{ {