diff options
Diffstat (limited to 'source/windowing/StarCanvasWidget.cpp')
-rw-r--r-- | source/windowing/StarCanvasWidget.cpp | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/source/windowing/StarCanvasWidget.cpp b/source/windowing/StarCanvasWidget.cpp new file mode 100644 index 0000000..3e58802 --- /dev/null +++ b/source/windowing/StarCanvasWidget.cpp @@ -0,0 +1,238 @@ +#include "StarCanvasWidget.hpp" + +namespace Star { + +CanvasWidget::CanvasWidget() { + m_captureKeyboard = false; + m_captureMouse = false; +} + +void CanvasWidget::setCaptureMouseEvents(bool captureMouse) { + m_captureMouse = captureMouse; +} + +void CanvasWidget::setCaptureKeyboardEvents(bool captureKeyboard) { + m_captureKeyboard = captureKeyboard; +} + +void CanvasWidget::clear() { + m_renderOps.clear(); +} + +void CanvasWidget::drawImage(String texName, Vec2F const& position, float scale, Vec4B const& color) { + m_renderOps.append(make_tuple(move(texName), position, scale, color, false)); +} + +void CanvasWidget::drawImageCentered(String texName, Vec2F const& position, float scale, Vec4B const& color) { + m_renderOps.append(make_tuple(move(texName), position, scale, color, true)); +} + +void CanvasWidget::drawImageRect(String texName, RectF const& texCoords, RectF const& screenCoords, Vec4B const& color) { + m_renderOps.append(make_tuple(move(texName), texCoords, screenCoords, color)); +} + +void CanvasWidget::drawDrawable(Drawable drawable, Vec2F const& screenPos) { + m_renderOps.append(make_tuple(move(drawable), screenPos)); +} + +void CanvasWidget::drawDrawables(List<Drawable> drawables, Vec2F const& screenPos) { + for (auto& drawable : drawables) + drawDrawable(move(drawable), screenPos); +} + +void CanvasWidget::drawTiledImage(String texName, float textureScale, Vec2D const& offset, RectF const& screenCoords, Vec4B const& color) { + m_renderOps.append(make_tuple(move(texName), textureScale, offset, screenCoords, color)); +} + +void CanvasWidget::drawLine(Vec2F const& begin, Vec2F const end, Vec4B const& color, float lineWidth) { + m_renderOps.append(make_tuple(begin, end, color, lineWidth)); +} + +void CanvasWidget::drawRect(RectF const& coords, Vec4B const& color) { + m_renderOps.append(make_tuple(coords, color)); +} + +void CanvasWidget::drawPoly(PolyF const& poly, Vec4B const& color, float lineWidth) { + m_renderOps.append(make_tuple(poly, color, lineWidth)); +} + +void CanvasWidget::drawTriangles(List<tuple<Vec2F, Vec2F, Vec2F>> const& triangles, Vec4B const& color) { + m_renderOps.append(make_tuple(triangles, color)); +} + +void CanvasWidget::drawText(String s, TextPositioning position, unsigned fontSize, Vec4B const& color, FontMode mode, float lineSpacing) { + m_renderOps.append(make_tuple(move(s), move(position), fontSize, color, mode, lineSpacing)); +} + +Vec2I CanvasWidget::mousePosition() const { + return m_mousePosition; +} + +List<CanvasWidget::ClickEvent> CanvasWidget::pullClickEvents() { + return take(m_clickEvents); +} + +List<CanvasWidget::KeyEvent> CanvasWidget::pullKeyEvents() { + return take(m_keyEvents); +} + +bool CanvasWidget::sendEvent(InputEvent const& event) { + if (!m_visible) + return false; + + auto& context = GuiContext::singleton(); + if (auto mouseButtonDown = event.ptr<MouseButtonDownEvent>()) { + if (inMember(*context.mousePosition(event)) && m_captureMouse) { + m_clickEvents.append({*context.mousePosition(event) - screenPosition(), mouseButtonDown->mouseButton, true}); + m_clickEvents.limitSizeBack(MaximumEventBuffer); + return true; + } + } else if (auto mouseButtonUp = event.ptr<MouseButtonUpEvent>()) { + if (m_captureMouse) { + m_clickEvents.append({*context.mousePosition(event) - screenPosition(), mouseButtonUp->mouseButton, false}); + m_clickEvents.limitSizeBack(MaximumEventBuffer); + return true; + } + } else if (event.is<MouseMoveEvent>()) { + m_mousePosition = *context.mousePosition(event) - screenPosition(); + return false; + } else if (auto keyDown = event.ptr<KeyDownEvent>()) { + if (m_captureKeyboard) { + m_keyEvents.append({keyDown->key, true}); + return true; + } + } else if (auto keyUp = event.ptr<KeyUpEvent>()) { + if (m_captureKeyboard) { + m_keyEvents.append({keyUp->key, false}); + m_keyEvents.limitSizeBack(MaximumEventBuffer); + return true; + } + } + + return Widget::sendEvent(event); +} + +KeyboardCaptureMode CanvasWidget::keyboardCaptured() const { + return m_captureKeyboard ? KeyboardCaptureMode::KeyEvents : KeyboardCaptureMode::None; +} + +void CanvasWidget::renderImpl() { + auto renderingOffset = Vec2F(screenPosition()); + + for (auto const& op : m_renderOps) { + if (auto args = op.ptr<ImageOp>()) + tupleUnpackFunction(bind(&CanvasWidget::renderImage, this, renderingOffset, _1, _2, _3, _4, _5), *args); + if (auto args = op.ptr<ImageRectOp>()) + tupleUnpackFunction(bind(&CanvasWidget::renderImageRect, this, renderingOffset, _1, _2, _3, _4), *args); + if (auto args = op.ptr<DrawableOp>()) + tupleUnpackFunction(bind(&CanvasWidget::renderDrawable, this, renderingOffset, _1, _2), *args); + if (auto args = op.ptr<TiledImageOp>()) + tupleUnpackFunction(bind(&CanvasWidget::renderTiledImage, this, renderingOffset, _1, _2, _3, _4, _5), *args); + if (auto args = op.ptr<LineOp>()) + tupleUnpackFunction(bind(&CanvasWidget::renderLine, this, renderingOffset, _1, _2, _3, _4), *args); + if (auto args = op.ptr<RectOp>()) + tupleUnpackFunction(bind(&CanvasWidget::renderRect, this, renderingOffset, _1, _2), *args); + if (auto args = op.ptr<PolyOp>()) + tupleUnpackFunction(bind(&CanvasWidget::renderPoly, this, renderingOffset, _1, _2, _3), *args); + if (auto args = op.ptr<TrianglesOp>()) + tupleUnpackFunction(bind(&CanvasWidget::renderTriangles, this, renderingOffset, _1, _2), *args); + if (auto args = op.ptr<TextOp>()) + tupleUnpackFunction(bind(&CanvasWidget::renderText, this, renderingOffset, _1, _2, _3, _4, _5, _6), *args); + } +} + +void CanvasWidget::renderImage(Vec2F const& renderingOffset, String const& texName, Vec2F const& position, float scale, Vec4B const& color, bool centered) { + auto& context = GuiContext::singleton(); + auto texSize = Vec2F(context.textureSize(texName)); + if (centered) { + auto screenCoords = RectF::withSize(renderingOffset * context.interfaceScale() + (position - scale * texSize / 2.0f) * context.interfaceScale(), texSize * scale * context.interfaceScale()); + context.drawQuad(texName, screenCoords, color); + } else { + auto screenCoords = RectF::withSize(renderingOffset * context.interfaceScale() + position * context.interfaceScale(), texSize * scale * context.interfaceScale()); + context.drawQuad(texName, screenCoords, color); + } +} + +void CanvasWidget::renderImageRect(Vec2F const& renderingOffset, String const& texName, RectF const& texCoords, RectF const& screenCoords, Vec4B const& color) { + auto& context = GuiContext::singleton(); + context.drawQuad(texName, texCoords, screenCoords.scaled(context.interfaceScale()).translated(renderingOffset * context.interfaceScale()), color); +} + +void CanvasWidget::renderDrawable(Vec2F const& renderingOffset, Drawable drawable, Vec2F const& screenPos) { + auto& context = GuiContext::singleton(); + drawable.scale(context.interfaceScale()); + context.drawDrawable(move(drawable), renderingOffset * context.interfaceScale() + screenPos * context.interfaceScale(), 1); +} + +void CanvasWidget::renderTiledImage(Vec2F const& renderingOffset, String const& texName, float textureScale, Vec2D const& offset, RectF const& screenCoords, Vec4B const& color) { + auto& context = GuiContext::singleton(); + + Vec2F texSize = Vec2F(context.textureSize(texName)); + Vec2F texScaledSize = texSize * textureScale; + Vec2I textureCount = Vec2I::ceil(screenCoords.size().piecewiseDivide(texScaledSize)) + Vec2I(2, 2); + Vec2F screenLowerLeft = screenCoords.min() - Vec2F(pfmod<double>(texScaledSize[0] - offset[0], texScaledSize[0]), pfmod<double>(texScaledSize[1] - offset[1], texScaledSize[1])); + + for (int x = 0; x < textureCount[0]; ++x) { + for (int y = 0; y < textureCount[1]; ++y) { + Vec2F screenPos = screenLowerLeft + texScaledSize.piecewiseMultiply({(float)x, (float)y}); + RectF screenRect = RectF::withSize(screenPos, texScaledSize); + + RectF limitedScreenRect; + limitedScreenRect.setXMin(max(screenRect.xMin(), screenCoords.xMin())); + limitedScreenRect.setYMin(max(screenRect.yMin(), screenCoords.yMin())); + limitedScreenRect.setXMax(min(screenRect.xMax(), screenCoords.xMax())); + limitedScreenRect.setYMax(min(screenRect.yMax(), screenCoords.yMax())); + + RectF limitedTexRect = limitedScreenRect.translated(-screenPos).scaled(1 / textureScale); + + if (limitedScreenRect.isEmpty()) + continue; + + context.drawQuad(texName, limitedTexRect, limitedScreenRect.translated(renderingOffset).scaled(context.interfaceScale()), color); + } + } +} + +void CanvasWidget::renderLine(Vec2F const& renderingOffset, Vec2F const& begin, Vec2F const end, Vec4B const& color, float lineWidth) { + auto& context = GuiContext::singleton(); + context.drawLine( + renderingOffset * context.interfaceScale() + begin * context.interfaceScale(), + renderingOffset * context.interfaceScale() + end * context.interfaceScale(), + color, lineWidth); +} + +void CanvasWidget::renderRect(Vec2F const& renderingOffset, RectF const& coords, Vec4B const& color) { + auto& context = GuiContext::singleton(); + context.drawQuad(coords.scaled(context.interfaceScale()).translated(renderingOffset * context.interfaceScale()), color); +} + +void CanvasWidget::renderPoly(Vec2F const& renderingOffset, PolyF poly, Vec4B const& color, float lineWidth) { + auto& context = GuiContext::singleton(); + poly.translate(renderingOffset); + context.drawInterfacePolyLines(poly, color, lineWidth); +} + +void CanvasWidget::renderTriangles(Vec2F const& renderingOffset, List<tuple<Vec2F, Vec2F, Vec2F>> const& triangles, Vec4B const& color) { + auto& context = GuiContext::singleton(); + auto translated = triangles.transformed([&renderingOffset](tuple<Vec2F, Vec2F, Vec2F> const& poly) { + return tuple<Vec2F, Vec2F, Vec2F>(get<0>(poly) + renderingOffset, + get<1>(poly) + renderingOffset, + get<2>(poly) + renderingOffset); + }); + context.drawInterfaceTriangles(translated, color); +} + +void CanvasWidget::renderText(Vec2F const& renderingOffset, String const& s, TextPositioning const& position, unsigned fontSize, Vec4B const& color, FontMode mode, float lineSpacing) { + auto& context = GuiContext::singleton(); + context.setFontSize(fontSize); + context.setFontColor(color); + context.setFontMode(mode); + context.setLineSpacing(lineSpacing); + + TextPositioning translatedPosition = position; + translatedPosition.pos += renderingOffset; + context.renderInterfaceText(s, translatedPosition); + context.setDefaultLineSpacing(); +} + +} |