Ejemplo n.º 1
0
 GuiWidget *findNextWidgetToFocus(WalkDirection dir)
 {
     PopupWidget *parentPopup = self().findParentPopup();
     Rectanglei const viewRect = self().root().viewRule().recti();
     bool escaped = false;
     auto *widget = self().walkInOrder(dir, [this, &viewRect, parentPopup, &escaped] (Widget &widget)
     {
         if (parentPopup && !widget.hasAncestor(*parentPopup))
         {
             // Cannot get out of the popup.
             escaped = true;
             return LoopAbort;
         }
         if (widget.canBeFocused() && widget.is<GuiWidget>())
         {
             // The widget's center must be in view.
             if (viewRect.contains(widget.as<GuiWidget>().rule().recti().middle()))
             {
                 // This is good.
                 return LoopAbort;
             }
         }
         return LoopContinue;
     });
     if (widget && !escaped)
     {
         return widget->asPtr<GuiWidget>();
     }
     return nullptr;
 }
Ejemplo n.º 2
0
    /**
     * Test if a clipped widget is contained within its ancestors' clip rectangles.
     */
    bool isClipCulled() const
    {
        bool wasClipped = false;
        Rectanglei visibleArea = self().root().viewRule().recti();

        for (Widget const *w = self().parentWidget(); w; w = w->parent())
        {
            if (!w->is<GuiWidget>()) continue;

            // Does this ancestor use child clipping?
            if (w->behavior().testFlag(ChildVisibilityClipping))
            {
                wasClipped = true;
                visibleArea &= w->as<GuiWidget>().rule().recti();
            }
        }
        if (!wasClipped) return false;

        if (self().isClipped())
        {
            int const CULL_SAFETY_WIDTH = 50; // avoid pop-in when scrolling

            // Clipped widgets are guaranteed to be within their rectangle.
            return !visibleArea.overlaps(self().rule().recti().expanded(
                                             GuiWidget::toDevicePixels(CULL_SAFETY_WIDTH)));
        }
        // Otherwise widgets may draw anywhere in the view.
        return visibleArea.isNull();
    }
Ejemplo n.º 3
0
static void drawRegion(memvolume_t &volume, Rectanglei const &rect, size_t start,
    size_t size, float const color[4])
{
    DENG2_ASSERT(start + size <= volume.size);

    int const bytesPerRow = (volume.size - sizeof(memzone_t)) / rect.height();
    float const toPixelScale = (float)rect.width() / (float)bytesPerRow;
    size_t const edge = rect.topLeft.x + rect.width();
    int x = (start % bytesPerRow) * toPixelScale + rect.topLeft.x;
    int y = start / bytesPerRow + rect.topLeft.y;
    int pixels = de::max<dint>(1, std::ceil(size * toPixelScale));

    while(pixels > 0)
    {
        int const availPixels = edge - x;
        int const usedPixels = de::min(availPixels, pixels);

        glColor4fv(color);
        glVertex2i(x, y);
        glVertex2i(x + usedPixels, y);

        pixels -= usedPixels;

        // Move to the next row.
        y++;
        x = rect.topLeft.x;
    }
}
Ejemplo n.º 4
0
bool WidgetList::Update(const Point2i& mousePosition,
                        const Point2i& lastMousePosition)
{
  Rectanglei clip;
  Rectanglei wlr = GetClip(clip);
  if (!wlr.GetSizeX() || !wlr.GetSizeY())
      return false;

  // Redraw the background
  bool updated = false;
  if (need_redrawing)
    RedrawBackground(wlr);

  for (std::list<Widget*>::const_iterator w=widget_list.begin();
      w != widget_list.end();
      w++)
  {
    Rectanglei r((*w)->GetPosition(), (*w)->GetSize());
    r.Clip(wlr);

    if (r.GetSizeX() && r.GetSizeY()) {
      SwapWindowClip(r);
      updated |= (*w)->Update(mousePosition, lastMousePosition);
      SwapWindowClip(r);
    }
  }

  if (updated)
    RedrawForeground();

  // Restore initial clip rectangle
  UnsetClip(clip);
  need_redrawing = false;
  return updated;
}
Ejemplo n.º 5
0
void LineEditWidget::draw()
{
    Rectanglei pos = rule().recti();

    // Temporary buffer for drawing.
    TextCanvas buf(pos.size());

    TextCanvas::Char::Attribs attr =
            (hasFocus()? TextCanvas::Char::Reverse : TextCanvas::Char::DefaultAttributes);
    buf.clear(TextCanvas::Char(' ', attr));

    buf.drawText(Vector2i(0, 0), prompt(), attr | TextCanvas::Char::Bold);

    // Underline the suggestion for completion.
    if(isSuggestingCompletion())
    {
        buf.setRichFormatRange(TextCanvas::Char::Underline, completionRange());
    }

    // Echo mode determines what we actually draw.
    String txt = text();
    if(echoMode() == PasswordEchoMode)
    {
        txt = String(txt.size(), '*');
    }
    buf.drawWrappedText(Vector2i(prompt().size(), 0), txt, lineWraps(), attr);

    targetCanvas().draw(buf, pos.topLeft);
}
Ejemplo n.º 6
0
QImage QtNativeFont::nativeFontRasterize(String const &text,
                                         Vector4ub const &foreground,
                                         Vector4ub const &background) const
{
#ifdef LIBGUI_ACCURATE_TEXT_BOUNDS
    Rectanglei const bounds = measure(text);
#else
    Rectanglei const bounds(Vector2i(0, -d->metrics->ascent()),
                            Vector2i(d->metrics->width(text),
                                     d->metrics->descent()));
#endif

    QColor const fgColor(foreground.x, foreground.y, foreground.z, foreground.w);
    QColor const bgColor(background.x, background.y, background.z, background.w);

    QImage img(QSize(bounds.width() + 1, bounds.height() + 1),
               QImage::Format_ARGB32);

    img.fill(bgColor.rgba());

    QPainter painter(&img);
    painter.setCompositionMode(QPainter::CompositionMode_Source);

    painter.setFont(d->font);
    painter.setPen(fgColor);
    painter.setBrush(bgColor);
    painter.drawText(-bounds.left(), -bounds.top(), text);

    return img;
}
Ejemplo n.º 7
0
void LabelWidget::draw()
{
    Rectanglei pos = rule().recti();
    TextCanvas buf(pos.size());
    buf.clear(d->background);

    // Use the wrapped lines to determine width and height.
    DENG2_ASSERT(!d->wraps.isEmpty());
    Vector2i labelSize(d->wraps.width(), d->wraps.height());

    // Determine position of the label based on alignment.
    Vector2i labelPos;
    if(d->align.testFlag(AlignRight))
    {
        labelPos.x = buf.width() - labelSize.x;
    }
    else if(!d->align.testFlag(AlignLeft))
    {
        labelPos.x = buf.width()/2 - labelSize.x/2;
    }
    if(d->align.testFlag(AlignBottom))
    {
        labelPos.y = buf.height() - labelSize.y;
    }
    else if(!d->align.testFlag(AlignTop))
    {
        labelPos.y = buf.height()/2 - labelSize.y/2;
    }

    buf.drawWrappedText(labelPos, d->label, d->wraps, d->attribs, d->align);

    targetCanvas().draw(buf, pos.topLeft);
}
Ejemplo n.º 8
0
void WidgetList::Draw(const Point2i &mousePosition)
{
  Rectanglei clip;
  Rectanglei wlr = GetClip(clip);
  if (!wlr.GetSizeX() || !wlr.GetSizeY())
      return;

  for (std::list<Widget*>::const_iterator w=widget_list.begin();
      w != widget_list.end();
      w++)
  {
    Rectanglei r((*w)->GetPosition(), (*w)->GetSize());
    r.Clip(wlr);

    if (r.GetSizeX() && r.GetSizeY()) {
      Rectanglei wr = r;
      SwapWindowClip(r);
      (*w)->RedrawBackground(wr);
      (*w)->Draw(mousePosition);
      (*w)->RedrawForeground();
      SwapWindowClip(r);
    }
  }

  // Restore initial clip rectangle
  UnsetClip(clip);
}
Ejemplo n.º 9
0
void BoundTexture2d::update_data(const Rectanglei& update_region,
        Texture::DataPixelFormat data_format, Texture::PixelType pixel_type, const void* data)
{
     glTexSubImage2D(GL_TEXTURE_2D, 0, update_region.left(), update_region.bottom(),
			update_region.width(), update_region.height(), static_cast<GLenum>(data_format),
			static_cast<GLenum>(pixel_type), data);
	CHECK_GL_ERROR(glTexSubImage2D);
}
Ejemplo n.º 10
0
static void drawChar(uchar ch, float x, float y, AbstractFont *font,
    int alignFlags, short /*textFlags*/)
{
    if(alignFlags & ALIGN_RIGHT)
    {
        x -= font->glyphPosCoords(ch).width();
    }
    else if(!(alignFlags & ALIGN_LEFT))
    {
        x -= font->glyphPosCoords(ch).width() / 2;
    }

    int const ascent = font->ascent();
    int const lineHeight = ascent? ascent : font->glyphPosCoords(ch).height();
    if(alignFlags & ALIGN_BOTTOM)
    {
        y -= topToAscent(font) + lineHeight;
    }
    else if(!(alignFlags & ALIGN_TOP))
    {
        y -= (topToAscent(font) + lineHeight) / 2;
    }

    LIBGUI_GL.glMatrixMode(GL_MODELVIEW);
    LIBGUI_GL.glTranslatef(x, y, 0);

    Rectanglei geometry = font->glyphPosCoords(ch);

    if(BitmapFont *bmapFont = font->maybeAs<BitmapFont>())
    {
        /// @todo Filtering should be determined at a higher level.
        /// @todo We should not need to re-bind this texture here.
        GL_BindTextureUnmanaged(bmapFont->textureGLName(), gl::ClampToEdge,
                                gl::ClampToEdge, filterUI? gl::Linear : gl::Nearest);

        geometry = geometry.expanded(bmapFont->textureMargin().toVector2i());
    }
    else if(CompositeBitmapFont *compFont = font->maybeAs<CompositeBitmapFont>())
    {
        GL_BindTexture(compFont->glyphTexture(ch));
        geometry = geometry.expanded(compFont->glyphTextureBorder(ch));
    }

    Vector2i coords[4] = { font->glyphTexCoords(ch).topLeft,
                           font->glyphTexCoords(ch).topRight(),
                           font->glyphTexCoords(ch).bottomRight,
                           font->glyphTexCoords(ch).bottomLeft() };

    GL_DrawRectWithCoords(geometry, coords);

    if(font->is<CompositeBitmapFont>())
    {
        GL_SetNoTexture();
    }

    LIBGUI_GL.glMatrixMode(GL_MODELVIEW);
    LIBGUI_GL.glTranslatef(-x, -y, 0);
}
Ejemplo n.º 11
0
void TextBox::Draw(const Point2i & mousePosition)
{
  Rectanglei clip;
  Rectanglei wlr = GetClip(clip);
  if (!wlr.GetSizeX() || !wlr.GetSizeY())
      return;

  Label::Draw(mousePosition);
  DrawCursor(position, cursor_pos);

  // Restore initial clip rectangle
  UnsetClip(clip);
}
Ejemplo n.º 12
0
Rectanglei QtNativeFont::nativeFontMeasure(String const &text) const
{
    Rectanglei rect = Rectanglei::fromQRect(d->metrics->boundingRect(text));

    if(rect.height() == 0)
    {
        // It seems measuring the bounds of a Tab character produces
        // strange results (position 100000?).
        rect = Rectanglei(0, 0, rect.width(), 0);
    }

    return rect;
}
Ejemplo n.º 13
0
  int SpriteAni::addFrame(int image_id, const Rectanglei &rect)
  {
    AniFrame *ani_frame = new AniFrame;
    ani_frame->id = (uint16)frame_seq.size();
    ani_frame->image = image_id;
    ani_frame->rect.x = rect.getLeft();
    ani_frame->rect.y = rect.getTop();
    ani_frame->rect.w = rect.getWidth();
    ani_frame->rect.h = rect.getHeight();

    frame_seq.push_back(ani_frame);

    return ani_frame->id;
  }
Ejemplo n.º 14
0
void Menu::RedrawBackground(const Rectanglei & rect) const
{
  if (!background) {
    return;
  }
  background->Blit(GetMainWindow(), rect, rect.GetPosition());
}
Ejemplo n.º 15
0
/*
 bool VirtualKeyboardParser::parsePolygon(Polygon &poly, const String& coords) {
 StringTokenizer tok(coords, ", ");
 for (String st = tok.nextToken(); !st.empty(); st = tok.nextToken()) {
 int x, y;
 if (sscanf(st.c_str(), "%d", &x) != 1)
 return parserError("Invalid coords for polygon area");
 st = tok.nextToken();
 if (sscanf(st.c_str(), "%d", &y) != 1)
 return parserError("Invalid coords for polygon area");
 poly.addPoint(x, y);
 }
 if (poly.getPointCount() < 3)
 return parserError("Invalid coords for polygon area");

 return true;
 }
 */
bool VirtualKeyboardParser::parseRectAsPolygon(Polygon &poly, const string& coords)
{
  Rectanglei rect;
  if (!parseRect(rect, coords))
    return false;
  poly.addPoint(rect.GetLeft(), rect.GetTop());
  poly.addPoint(rect.GetRight(), rect.GetTop());
  poly.addPoint(rect.GetRight(), rect.GetBottom());
  poly.addPoint(rect.GetLeft(), rect.GetBottom());
  return true;
}
Ejemplo n.º 16
0
void RectangleTest::access() {
    Rectanglei rect({34, 23}, {47, 30});
    constexpr Rectanglei crect({34, 23}, {47, 30});

    CORRADE_COMPARE(rect.bottomLeft(), Vector2i(34, 23));
    CORRADE_COMPARE(rect.topRight(), Vector2i(47, 30));
    CORRADE_COMPARE(rect.bottom(), 23);
    CORRADE_COMPARE(rect.top(), 30);
    CORRADE_COMPARE(rect.left(), 34);
    CORRADE_COMPARE(rect.right(), 47);
    CORRADE_COMPARE(rect.bottomLeft(), Vector2i(34, 23));
    CORRADE_COMPARE(rect.topRight(), Vector2i(47, 30));

    constexpr Int bottom = crect.bottom();
    constexpr Int top = crect.top();
    constexpr Int left = crect.left();
    constexpr Int right = crect.right();
    CORRADE_COMPARE(bottom, 23);
    CORRADE_COMPARE(top, 30);
    CORRADE_COMPARE(left, 34);
    CORRADE_COMPARE(right, 47);

    constexpr Vector2i bottomLeft = crect.bottomLeft();
    constexpr Vector2i topRight = crect.topRight();
    CORRADE_COMPARE(bottomLeft, Vector2i(34, 23));
    CORRADE_COMPARE(topRight, Vector2i(47, 30));

    CORRADE_COMPARE(rect.topLeft(), Vector2i(34, 30));
    CORRADE_COMPARE(rect.bottomRight(), Vector2i(47, 23));
}
Ejemplo n.º 17
0
    void draw()
    {
        Rectanglei pos;
        if(self.hasChangedPlace(pos) || !bgBuf->isReady())
        {
            // Update the background quad.
            VertexBuf::Builder bgVerts;
            self.glMakeGeometry(bgVerts);
            bgBuf->setVertices(gl::TriangleStrip, bgVerts, gl::Static);
        }

        // Draw the background.
        background.draw();

        Rectanglei vp = self.viewport();
        if(vp.height() > 0)
        {
            GLState &st = GLState::push();
            // Leave room for the indicator in the scissor.
            st.setScissor(vp.adjusted(Vector2i(), Vector2i(self.rightMargin(), 0)));

            // First draw the shadow of the text.
            uMvpMatrix = projMatrix * Matrix4f::translate(
                         Vector2f(vp.topLeft + Vector2i(0, contentOffsetForDrawing)));
            uShadowColor = Vector4f(0, 0, 0, 1);
            contents.draw();

            // Draw the text itself.
            uMvpMatrix = projMatrix * Matrix4f::translate(
                         Vector2f(vp.topLeft + Vector2i(0, contentOffsetForDrawing - 1)));
            uShadowColor = Vector4f(1, 1, 1, 1);
            contents.draw();

            GLState::pop();
        }

        // We don't need to keep all entries ready for drawing immediately.
        releaseExcessComposedEntries();
    }
Ejemplo n.º 18
0
inline bool PhysicalObj::Intersect(const Rectanglei & rect) const
{
  int dim = m_width - m_test_right - m_test_left;
  dim = dim ? dim : 1;

  int obj_test1 = GetX() + m_test_left;
  int obj_test2 = obj_test1 + dim - 1;
  int test1 = rect.GetPositionX();
  int test2 = test1 + rect.GetSizeX() - 1;

  if (obj_test2 >= test1 && obj_test1 <= test2) {
    dim = m_height - m_test_bottom - m_test_top;
    dim = dim ? dim : 1;
    obj_test1 = GetY() + m_test_top;
    obj_test2 = obj_test1 + dim - 1;
    test1 = rect.GetPositionY();
    test2 = test1 + rect.GetSizeY() - 1;

    if (obj_test2 >= test1 && obj_test1 <= test2)
      return true;
  }
  return false;
}
Ejemplo n.º 19
0
duint CanvasWindow::grabAsTexture(Rectanglei const &area, GrabMode mode) const
{
    QSize size;
    if(mode == GrabHalfSized)
    {
        size = QSize(area.width()/2, area.height()/2);
    }
    return d->canvas->grabAsTexture(
                QRect(area.left(), area.top(), area.width(), area.height()), size);
}
Ejemplo n.º 20
0
    void glSubImage(int level, Rectanglei const &rect, Image const &image,
                    CubeFace face = PositiveX)
    {
        auto const &glFormat = image.glFormat();

        LIBGUI_GL.glPixelStorei(GL_UNPACK_ALIGNMENT,  GLint(glFormat.rowAlignment));
        LIBGUI_GL.glPixelStorei(GL_UNPACK_ROW_LENGTH, GLint(image.width()));

        int const bytesPerPixel = image.depth() / 8;

        LIBGUI_GL.glTexSubImage2D(isCube()? glFace(face) : texTarget,
                                  level, rect.left(), rect.top(), rect.width(), rect.height(),
                                  glFormat.format, glFormat.type,
                                  static_cast<dbyte const *>(image.bits()) +
                                  bytesPerPixel * rect.left() + image.stride() * rect.top());

        LIBGUI_GL.glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);

        LIBGUI_ASSERT_GL_OK();
    }
Ejemplo n.º 21
0
    /**
     * Submits the image to the backing store, or commits it if no backing
     * store is available.
     *
     * @param image  Image.
     * @param rect   Rectangle for the image determined by an IAllocator.
     */
    void submitImage(Image const &image, Rectanglei const &rect)
    {
        Rectanglei const noBorders  = rect.shrunk(border);
        Rectanglei const withMargin = rect.expanded(margin);

        if (hasBacking())
        {
            // The margin is cleared to transparent black.
            backing.fill(withMargin, Image::Color(0, 0, 0, 0));

            if (border > 0)
            {
                if (flags.testFlag(WrapBordersInBackingStore))
                {
                    // Wrap using the source image (left, right, top, bottom edges).
                    backing.drawPartial(image, Rectanglei(0, 0, border, image.height()),
                                           rect.topRight() + Vector2i(-border, border));

                    backing.drawPartial(image, Rectanglei(image.width() - border, 0,
                                                             border, image.height()),
                                           rect.topLeft + Vector2i(0, border));

                    backing.drawPartial(image, Rectanglei(0, 0, image.width(), border),
                                           rect.bottomLeft() + Vector2i(border, -border));

                    backing.drawPartial(image, Rectanglei(0, image.height() - border,
                                                             image.width(), border),
                                           rect.topLeft + Vector2i(border, 0));
                }
            }
            backing.draw(image, noBorders.topLeft);

            //backing.toQImage().save(QString("backing-%1.png").arg(uint64_t(this)));

            markAsChanged(rect);
        }
        else
        {
            // No backing, must commit immediately.
            if (border > 0)
            {
                // Expand with borders (repeat edges).
                QImage const srcImg = image.toQImage();
                int const sw = srcImg.width();
                int const sh = srcImg.height();

                QImage bordered(QSize(rect.width(), rect.height()), srcImg.format());
                int const w = bordered.width();
                int const h = bordered.height();

                QPainter painter(&bordered);
                painter.setCompositionMode(QPainter::CompositionMode_Source);
                painter.fillRect(bordered.rect(), QColor(0, 0, 0, 0));

                /// @todo This really only works for a border of 1 pixels. Should
                /// repeat the same outmost edge pixels for every border. -jk

                painter.drawImage(border, border, srcImg);
                painter.drawImage(border, 0,     srcImg, 0, 0, sw, 1); // top
                painter.drawImage(border, h - 1, srcImg, 0, sh - 1, sw, 1); // bottom
                painter.drawImage(0, border,     srcImg, 0, 0, 1, sh); // left
                painter.drawImage(w - 1, border, srcImg, sw - 1, 0, 1, sh); // right

                // Corners.
                painter.drawImage(0, 0,         srcImg, 0, 0, 1, 1);
                painter.drawImage(w - 1, 0,     srcImg, sw - 1, 0, 1, 1);
                painter.drawImage(0, h - 1,     srcImg, 0, sh - 1, 1, 1);
                painter.drawImage(w - 1, h - 1, srcImg, sw - 1, sh - 1, 1, 1);

                self().commit(bordered, rect.topLeft);
            }
            else
            {
                self().commit(image, noBorders.topLeft);
            }
        }
    }
Ejemplo n.º 22
0
namespace Magnum { namespace Math { namespace Geometry { namespace Test {

class RectangleTest: public Corrade::TestSuite::Tester {
    public:
        RectangleTest();

        void construct();
        void constructDefault();
        void constructFromSize();
        void constructConversion();
        void constructCopy();

        void access();
        void compare();
        void size();

        void debug();
};

typedef Geometry::Rectangle<Float> Rectangle;
typedef Geometry::Rectangle<Int> Rectanglei;
typedef Vector2<Int> Vector2i;

RectangleTest::RectangleTest() {
    addTests({&RectangleTest::construct,
              &RectangleTest::constructDefault,
              &RectangleTest::constructFromSize,
              &RectangleTest::constructConversion,
              &RectangleTest::constructCopy,

              &RectangleTest::access,
              &RectangleTest::compare,
              &RectangleTest::size,

              &RectangleTest::debug});
}

void RectangleTest::construct() {
    constexpr Rectanglei a({3, 5}, {23, 78});
    CORRADE_COMPARE(a, Rectanglei({3, 5}, {23, 78}));
}

void RectangleTest::constructDefault() {
    constexpr Rectanglei a;
    CORRADE_COMPARE(a, Rectanglei({0, 0}, {0, 0}));
}

void RectangleTest::constructFromSize() {
    CORRADE_COMPARE(Rectanglei::fromSize({3, 5}, {23, 78}), Rectanglei({3, 5}, {26, 83}));
}

void RectangleTest::constructConversion() {
    constexpr Rectangle a({1.3f, 2.7f}, {-15.0f, 7.0f});
    #ifndef CORRADE_GCC46_COMPATIBILITY
    constexpr /* Not constexpr under GCC < 4.7 */
    #endif
    Rectanglei b(a);
    CORRADE_COMPARE(b, Rectanglei({1, 2}, {-15, 7}));

    /* Implicit conversion is not allowed */
    CORRADE_VERIFY(!(std::is_convertible<Rectangle, Rectanglei>::value));
}

void RectangleTest::constructCopy() {
    constexpr Rectanglei a({3, 5}, {23, 78});
    constexpr Rectanglei b(a);
    CORRADE_COMPARE(b, Rectanglei({3, 5}, {23, 78}));
}

void RectangleTest::access() {
    Rectanglei rect({34, 23}, {47, 30});
    constexpr Rectanglei crect({34, 23}, {47, 30});

    CORRADE_COMPARE(rect.bottomLeft(), Vector2i(34, 23));
    CORRADE_COMPARE(rect.topRight(), Vector2i(47, 30));
    CORRADE_COMPARE(rect.bottom(), 23);
    CORRADE_COMPARE(rect.top(), 30);
    CORRADE_COMPARE(rect.left(), 34);
    CORRADE_COMPARE(rect.right(), 47);
    CORRADE_COMPARE(rect.bottomLeft(), Vector2i(34, 23));
    CORRADE_COMPARE(rect.topRight(), Vector2i(47, 30));

    constexpr Int bottom = crect.bottom();
    constexpr Int top = crect.top();
    constexpr Int left = crect.left();
    constexpr Int right = crect.right();
    CORRADE_COMPARE(bottom, 23);
    CORRADE_COMPARE(top, 30);
    CORRADE_COMPARE(left, 34);
    CORRADE_COMPARE(right, 47);

    constexpr Vector2i bottomLeft = crect.bottomLeft();
    constexpr Vector2i topRight = crect.topRight();
    CORRADE_COMPARE(bottomLeft, Vector2i(34, 23));
    CORRADE_COMPARE(topRight, Vector2i(47, 30));

    CORRADE_COMPARE(rect.topLeft(), Vector2i(34, 30));
    CORRADE_COMPARE(rect.bottomRight(), Vector2i(47, 23));
}

void RectangleTest::compare() {
    CORRADE_VERIFY(Rectanglei({34, 23}, {47, 30}) == Rectanglei({34, 23}, {47, 30}));
    CORRADE_VERIFY(Rectanglei({34, 23}, {47, 30}) != Rectanglei({34, 23}, {48, 30}));
    CORRADE_VERIFY(Rectanglei({34, 23}, {47, 30}) != Rectanglei({35, 23}, {47, 30}));
}

void RectangleTest::size() {
    Rectanglei rect({34, 23}, {47, 30});

    CORRADE_COMPARE(rect.size(), Vector2i(13, 7));
    CORRADE_COMPARE(rect.width(), 13);
    CORRADE_COMPARE(rect.height(), 7);
}

void RectangleTest::debug() {
    std::ostringstream o;
    Debug(&o) << Rectanglei({34, 23}, {47, 30});

    CORRADE_COMPARE(o.str(), "Rectangle({34, 23}, {47, 30})\n");
}

}}}}