Skip to content

Commit

Permalink
Widgets|libappfw: Improved point/pixel conversions
Browse files Browse the repository at this point in the history
There is now a clear way to convert between points and pixels.

LabelWidget’s override size for images is a Rule so it can be dynamically updated.
  • Loading branch information
skyjake committed Nov 18, 2018
1 parent be44767 commit 32a94dc
Show file tree
Hide file tree
Showing 20 changed files with 125 additions and 100 deletions.
Expand Up @@ -83,17 +83,17 @@ class LIBAPPFW_PUBLIC AtlasProceduralImage : public ProceduralImage
_image = image;
_needUpdate = true;
_imageOwned = true;
setSize(image.size());
setPointSize(image.size() * image.pointRatio());
}

void setPreallocatedImage(Id const &id)
void setPreallocatedImage(Id const &id, float pointRatio = 1.f)
{
_image = Image();
_needUpdate = false;
_imageOwned = false;
_id = id;
_atlas = &ownerAtlas();
setSize(_atlas->imageRect(id).size());
setPointSize(_atlas->imageRect(id).size() * pointRatio);
}

bool update()
Expand Down
23 changes: 15 additions & 8 deletions doomsday/sdk/libappfw/include/de/framework/guiwidget.h
Expand Up @@ -487,20 +487,27 @@ public slots:
static Rectanglef normalizedRect(Rectanglei const &rect,
Rectanglei const &containerRect);

static float toDevicePixels(float logicalPixels);
static float pointsToPixels(float points);
static float pixelsToPoints(float pixels);

inline static int toDevicePixels(int logicalPixels) {
return int(toDevicePixels(float(logicalPixels)));
inline static int pointsToPixels(int points) {
return int(pointsToPixels(float(points)));
}

inline static duint toDevicePixels(duint logicalPixels) {
return duint(toDevicePixels(float(logicalPixels)));
inline static duint pointsToPixels(duint points) {
return duint(pointsToPixels(float(points)));
}

template <typename Vector2>
static Vector2 toDevicePixels(Vector2 const &type) {
return Vector2(typename Vector2::ValueType(toDevicePixels(type.x)),
typename Vector2::ValueType(toDevicePixels(type.y)));
static Vector2 pointsToPixels(Vector2 const &type) {
return Vector2(typename Vector2::ValueType(pointsToPixels(type.x)),
typename Vector2::ValueType(pointsToPixels(type.y)));
}

template <typename Vector2>
static Vector2 pixelsToPoints(Vector2 const &type) {
return Vector2(typename Vector2::ValueType(pixelsToPoints(type.x)),
typename Vector2::ValueType(pixelsToPoints(type.y)));
}

static ColorTheme invertColorTheme(ColorTheme theme);
Expand Down
8 changes: 4 additions & 4 deletions doomsday/sdk/libappfw/include/de/framework/proceduralimage.h
Expand Up @@ -42,13 +42,13 @@ class LIBAPPFW_PUBLIC ProceduralImage
typedef Vector4f Color;

public:
ProceduralImage(Size const &size = Size());
ProceduralImage(Size const &pointSize = Size());
virtual ~ProceduralImage();

Size size() const;
Size pointSize() const; // in points
Color color() const;

void setSize(Size const &size);
void setPointSize(Size const &pointSize);
void setColor(Color const &color);

/**
Expand All @@ -66,7 +66,7 @@ class LIBAPPFW_PUBLIC ProceduralImage
DENG2_CAST_METHODS()

private:
Size _size;
Size _pointSize;
Color _color;
};

Expand Down
Expand Up @@ -34,7 +34,10 @@ class StyleProceduralImage : public ProceduralImage
{
public:
StyleProceduralImage(DotPath const &styleImageId, GuiWidget &owner, float angle = 0)
: _owner(owner), _imageId(styleImageId), _id(Id::None), _angle(angle)
: _owner(owner)
, _imageId(styleImageId)
, _id(Id::None)
, _angle(angle)
{
if (_owner.hasRoot())
{
Expand All @@ -60,8 +63,9 @@ class StyleProceduralImage : public ProceduralImage

void alloc()
{
const Image &img = Style::get().images().image(_imageId);
setPointSize(img.size() * img.pointRatio());
_id = root().styleTexture(_imageId);
setSize(root().atlas().imageRect(_id).size());
}

Id const &allocId() const
Expand Down
14 changes: 11 additions & 3 deletions doomsday/sdk/libappfw/include/de/widgets/labelwidget.h
Expand Up @@ -200,11 +200,19 @@ class LIBAPPFW_PUBLIC LabelWidget : public GuiWidget, public IAssetGroup
* The image's actual size will be overridden by this size.
* @param size Image size.
*/
void setOverrideImageSize(Vector2f const &size);
void setOverrideImageSize(const Rule &width, const Rule &height);

Vector2f overrideImageSize() const;
void setOverrideImageSize(const ISizeRule &size)
{
setOverrideImageSize(size.width(), size.height());
}

void setOverrideImageSize(const Rule &widthAndHeight)
{
setOverrideImageSize(widthAndHeight, widthAndHeight);
}

void setOverrideImageSize(float widthAndHeight);
RulePair overrideImageSize() const;

void setImageScale(float scaleFactor);

Expand Down
2 changes: 1 addition & 1 deletion doomsday/sdk/libappfw/src/childwidgetorganizer.cpp
Expand Up @@ -516,7 +516,7 @@ DENG2_PIMPL(ChildWidgetOrganizer)
// This will ensure that differences in item heights will not accumulate
// and cause the estimated PVS to become too inaccurate.
float error = virtualStrut->value() - estimated.start * averageItemHeight;
correctionPerUnit = -error / GuiWidget::toDevicePixels(100);
correctionPerUnit = -error / GuiWidget::pointsToPixels(100);
totalCorrection = de::abs(error);
}
// Apply correction to the virtual strut.
Expand Down
2 changes: 1 addition & 1 deletion doomsday/sdk/libappfw/src/dialogs/messagedialog.cpp
Expand Up @@ -45,7 +45,7 @@ DENG_GUI_PIMPL(MessageDialog)
title->setSizePolicy(ui::Fixed, ui::Expand);
title->setAlignment(ui::AlignLeft);
title->setTextAlignment(ui::AlignRight);
title->setOverrideImageSize(title->font().ascent().valuei());
title->setOverrideImageSize(title->font().ascent());
title->setImageColor(style().colors().colorf("accent"));
title->setTextGap("gap");
title->setTextLineAlignment(ui::AlignLeft);
Expand Down
34 changes: 22 additions & 12 deletions doomsday/sdk/libappfw/src/guiwidget.cpp
Expand Up @@ -175,7 +175,7 @@ DENG2_PIMPL(GuiWidget)

// Clipped widgets are guaranteed to be within their rectangle.
return !visibleArea.overlaps(self().rule().recti().expanded(
GuiWidget::toDevicePixels(CULL_SAFETY_WIDTH)));
GuiWidget::pointsToPixels(CULL_SAFETY_WIDTH)));
}
// Otherwise widgets may draw anywhere in the view.
return visibleArea.isNull();
Expand All @@ -188,7 +188,7 @@ DENG2_PIMPL(GuiWidget)
blur.reset(new BlurState);

// The blurred version of the view is downsampled.
blur->size = (self().root().viewSize() / GuiWidget::toDevicePixels(4)).max(Vector2ui(1, 1));
blur->size = (self().root().viewSize() / GuiWidget::pointsToPixels(4)).max(Vector2ui(1, 1));

for (int i = 0; i < 2; ++i)
{
Expand Down Expand Up @@ -463,7 +463,7 @@ DENG2_PIMPL(GuiWidget)
break;
}
// Very close edges are considered contacting.
if (edgeDistance >= 0 && edgeDistance < toDevicePixels(5))
if (edgeDistance >= 0 && edgeDistance < pointsToPixels(5))
{
return edgeDistance;
}
Expand Down Expand Up @@ -555,9 +555,14 @@ DENG2_PIMPL(GuiWidget)
// updateStyle() will be called during the next update().
}

static float toDevicePixels(double logicalPixels)
static inline float pointsToPixels(double points)
{
return float(logicalPixels) * DENG2_BASE_GUI_APP->pixelRatio().value();
return float(points) * DENG2_BASE_GUI_APP->pixelRatio().value();
}

static inline float pixelsToPoints(double pixels)
{
return float(pixels) / DENG2_BASE_GUI_APP->pixelRatio().value();
}
};

Expand Down Expand Up @@ -701,9 +706,14 @@ Rectanglef GuiWidget::normalizedRect(de::Rectanglei const &rect,
rectf.bottom() / contSize.y));
}

float GuiWidget::toDevicePixels(float logicalPixels)
float GuiWidget::pointsToPixels(float points)
{
return Impl::pointsToPixels(points);
}

float GuiWidget::pixelsToPoints(float pixels)
{
return Impl::toDevicePixels(logicalPixels);
return Impl::pixelsToPoints(pixels);
}

Rectanglef GuiWidget::normalizedRect() const
Expand Down Expand Up @@ -1194,14 +1204,14 @@ PopupWidget *GuiWidget::findParentPopup() const
void GuiWidget::glMakeGeometry(GuiVertexBuilder &verts)
{
auto &rootWgt = root();
float const thick = d->toDevicePixels(d->background.thickness);
float const thick = d->pointsToPixels(d->background.thickness);

// Is there a solid fill?
if (d->background.solidFill.w > 0)
{
if (d->background.type == Background::GradientFrameWithRoundedFill)
{
Rectanglei const recti = rule().recti().shrunk(d->toDevicePixels(2));
Rectanglei const recti = rule().recti().shrunk(d->pointsToPixels(2));
verts.makeQuad(recti.shrunk(thick), d->background.solidFill,
rootWgt.atlas().imageRectf(rootWgt.solidRoundCorners()).middle());
verts.makeFlexibleFrame(recti, thick, d->background.solidFill,
Expand All @@ -1225,19 +1235,19 @@ void GuiWidget::glMakeGeometry(GuiVertexBuilder &verts)
case Background::GradientFrameWithThinBorder:
if (d->background.type == Background::GradientFrameWithThinBorder)
{
verts.makeFlexibleFrame(rule().recti().shrunk(d->toDevicePixels(2)),
verts.makeFlexibleFrame(rule().recti().shrunk(d->pointsToPixels(2)),
thick,
Vector4f(0, 0, 0, .5f),
rootWgt.atlas().imageRectf(rootWgt.boldRoundCorners()));
}
verts.makeFlexibleFrame(rule().recti().shrunk(d->toDevicePixels(1)),
verts.makeFlexibleFrame(rule().recti().shrunk(d->pointsToPixels(1)),
thick,
d->background.color,
rootWgt.atlas().imageRectf(rootWgt.boldRoundCorners()));
break;

case Background::Rounded:
verts.makeFlexibleFrame(rule().recti().shrunk(d->toDevicePixels(d->background.thickness - 4)),
verts.makeFlexibleFrame(rule().recti().shrunk(d->pointsToPixels(d->background.thickness - 4)),
thick,
d->background.color,
rootWgt.atlas().imageRectf(rootWgt.roundCorners()));
Expand Down
12 changes: 6 additions & 6 deletions doomsday/sdk/libappfw/src/proceduralimage.cpp
Expand Up @@ -20,26 +20,26 @@

namespace de {

ProceduralImage::ProceduralImage(Size const &size)
: _size(size), _color(1, 1, 1, 1)
ProceduralImage::ProceduralImage(Size const &pointSize)
: _pointSize(pointSize), _color(1, 1, 1, 1)
{}

ProceduralImage::~ProceduralImage()
{}

ProceduralImage::Size ProceduralImage::size() const
ProceduralImage::Size ProceduralImage::pointSize() const
{
return _size;
return _pointSize;
}

ProceduralImage::Color ProceduralImage::color() const
{
return _color;
}

void ProceduralImage::setSize(Size const &size)
void ProceduralImage::setPointSize(Size const &pointSize)
{
_size = size;
_pointSize = pointSize;
}

void ProceduralImage::setColor(Color const &color)
Expand Down
6 changes: 3 additions & 3 deletions doomsday/sdk/libappfw/src/vrwindowtransform.cpp
Expand Up @@ -72,13 +72,13 @@ DENG2_PIMPL(VRWindowTransform)
#if defined (DENG_MOBILE)
return 1.0f;
#else
if (GuiWidget::toDevicePixels(1) == 1) return 1.0f; // Not enough pixels for good-quality scaling.
if (GuiWidget::pointsToPixels(1) == 1) return 1.0f; // Not enough pixels for good-quality scaling.

// Since the UI style doesn't yet support scaling at runtime based on
// display resolution (or any other factor).
return 1.f / Rangef(.5f, 1.0f)
.clamp((width()) /
GuiWidget::toDevicePixels(640.f));
GuiWidget::pointsToPixels(640.f));
#endif
}

Expand Down Expand Up @@ -378,7 +378,7 @@ Vector2ui VRWindowTransform::logicalRootSize(Vector2ui const &physicalWindowSize
// Adjust effective UI size for stereoscopic rendering.
size.x = size.y * d->vrCfg.oculusRift().aspect();
//size.y *= d->vrCfg.oculusRift().aspect();
size *= GuiWidget::toDevicePixels(1) * .75f;
size *= GuiWidget::pointsToPixels(1) * .75f;
break;

// Allow UI to squish in top/bottom and SBS mode: 3D hardware will unsquish them
Expand Down
4 changes: 2 additions & 2 deletions doomsday/sdk/libappfw/src/widgets/dialogwidget.cpp
Expand Up @@ -176,7 +176,7 @@ DENG_GUI_PIMPL(DialogWidget)
heading->setSizePolicy(ui::Expand, ui::Expand);
heading->setTextColor("accent");
heading->setImageColor(style().colors().colorf("accent"));
heading->setOverrideImageSize(heading->font().ascent().valuei());
heading->setOverrideImageSize(heading->font().ascent());
heading->setTextGap("dialog.gap");
heading->setTextAlignment(ui::AlignRight);
heading->setTextLineAlignment(ui::AlignLeft);
Expand Down Expand Up @@ -345,7 +345,7 @@ DENG_GUI_PIMPL(DialogWidget)
ButtonWidget &but = widget.as<ButtonWidget>();

// Button images must be a certain size.
but.setOverrideImageSize(style().fonts().font("default").height().valuei());
but.setOverrideImageSize(style().fonts().font("default").height());

// Set default label?
if (item.label().isEmpty())
Expand Down
6 changes: 3 additions & 3 deletions doomsday/sdk/libappfw/src/widgets/foldpanelwidget.cpp
Expand Up @@ -53,7 +53,7 @@ DENG2_PIMPL_NOREF(FoldPanelWidget)
bool changed = animating;

float target = (fold.isOpen()? 0 : 90);
if (target != angle.target())
if (!fequal(target, angle.target()))
{
angle.setValue(target, INDICATOR_ANIM_SPAN);
animating = true;
Expand All @@ -65,8 +65,8 @@ DENG2_PIMPL_NOREF(FoldPanelWidget)
needSize = false;
changed = true;

float h = fold.title().font().height().value();
setSize(Vector2f(h, h));
const float h = pixelsToPoints(fold.title().font().height().value());
setPointSize({h, h});
}

// Stop animating?
Expand Down

0 comments on commit 32a94dc

Please sign in to comment.