300 lines
8.6 KiB
C++
300 lines
8.6 KiB
C++
/*
|
|
* SPDX-License-Identifier: GPL-3.0-only
|
|
* MuseScore-CLA-applies
|
|
*
|
|
* MuseScore
|
|
* Music Composition & Notation
|
|
*
|
|
* Copyright (C) 2021 MuseScore BVBA and others
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 3 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
#ifndef MU_DRAW_PAINTER_H
|
|
#define MU_DRAW_PAINTER_H
|
|
|
|
#include <list>
|
|
#include <stack>
|
|
|
|
#include "ipaintprovider.h"
|
|
|
|
#include "types/string.h"
|
|
|
|
#include "types/color.h"
|
|
#include "types/geometry.h"
|
|
#include "types/drawtypes.h"
|
|
#include "types/font.h"
|
|
#include "types/pen.h"
|
|
#include "types/pixmap.h"
|
|
|
|
class QPaintDevice;
|
|
|
|
#ifndef NO_QT_SUPPORT
|
|
class QPainter;
|
|
#endif
|
|
|
|
namespace mu::draw {
|
|
class Painter
|
|
{
|
|
public:
|
|
Painter(IPaintProviderPtr provider, const std::string& name);
|
|
|
|
#ifndef NO_QT_SUPPORT
|
|
Painter(QPaintDevice* dp, const std::string& name);
|
|
Painter(QPainter* qp, const std::string& name, bool ownsQPainter = false);
|
|
#endif
|
|
|
|
~Painter();
|
|
|
|
IPaintProviderPtr provider() const;
|
|
void setProvider(const IPaintProviderPtr& p, bool reinit = true);
|
|
|
|
bool isActive() const;
|
|
bool endDraw();
|
|
|
|
//! NOTE These are methods for debugging and automated testing.
|
|
void beginObject(const std::string& name, const PointF& pagePos);
|
|
void endObject();
|
|
|
|
// state
|
|
void setAntialiasing(bool arg);
|
|
void setCompositionMode(CompositionMode mode);
|
|
|
|
void setFont(const Font& font);
|
|
const Font& font() const;
|
|
|
|
void setPen(const Pen& pen);
|
|
inline void setPen(const Color& color);
|
|
void setNoPen();
|
|
const Pen& pen() const;
|
|
|
|
void setBrush(const Brush& brush);
|
|
const Brush& brush() const;
|
|
|
|
void setWorldTransform(const Transform& matrix, bool combine = false);
|
|
const Transform& worldTransform() const;
|
|
void scale(double sx, double sy);
|
|
void rotate(double angle);
|
|
void translate(double dx, double dy);
|
|
inline void translate(const PointF& offset);
|
|
|
|
RectF window() const;
|
|
void setWindow(const RectF& window);
|
|
RectF viewport() const;
|
|
void setViewport(const RectF& viewport);
|
|
|
|
void save();
|
|
void restore();
|
|
|
|
// drawing
|
|
void fillPath(const PainterPath& path, const Brush& brush);
|
|
void drawPath(const PainterPath& path);
|
|
void strokePath(const PainterPath& path, const Pen& pen);
|
|
|
|
void drawLines(const LineF* lines, size_t lineCount);
|
|
void drawLines(const PointF* pointPairs, size_t lineCount);
|
|
inline void drawLine(const LineF& line);
|
|
inline void drawLine(const PointF& p1, const PointF& p2);
|
|
inline void drawLines(const std::vector<LineF>& lines);
|
|
|
|
//! NOTE Potentially dangerous method.
|
|
//! Most of them are cut with fractional values.
|
|
//! Fractions are also passed to this method, and, accordingly, the fractional part is discarded.
|
|
inline void drawLine(int x1, int y1, int x2, int y2);
|
|
|
|
inline void drawRect(const RectF& rect);
|
|
|
|
//! NOTE Potentially dangerous method.
|
|
//! Most of them are cut with fractional values.
|
|
//! Fractions are also passed to this method, and, accordingly, the fractional part is discarded.
|
|
inline void drawRect(int x1, int y1, int w, int h);
|
|
|
|
void drawRects(const RectF* rects, size_t rectCount);
|
|
|
|
void drawRoundedRect(const RectF& rect, double xRadius, double yRadius);
|
|
|
|
void drawEllipse(const RectF& rect);
|
|
inline void drawEllipse(const PointF& center, double rx, double ry);
|
|
|
|
void drawPolyline(const PointF* points, size_t pointCount);
|
|
inline void drawPolyline(const PolygonF& polyline);
|
|
|
|
void drawPolygon(const PointF* points, size_t pointCount, FillRule fillRule = FillRule::OddEvenFill);
|
|
inline void drawPolygon(const PolygonF& polygon, FillRule fillRule = FillRule::OddEvenFill);
|
|
|
|
void drawConvexPolygon(const PointF* points, size_t pointCount);
|
|
inline void drawConvexPolygon(const PolygonF& polygon);
|
|
|
|
void drawArc(const RectF& rect, int a, int alen);
|
|
|
|
void drawText(const PointF& point, const String& text);
|
|
void drawText(const RectF& rect, int flags, const String& text);
|
|
|
|
//! NOTE Potentially dangerous method.
|
|
//! Most of them are cut with fractional values.
|
|
//! Fractions are also passed to this method, and, accordingly, the fractional part is discarded.
|
|
inline void drawText(int x, int y, const String& text);
|
|
|
|
//! NOTE workaround for https://musescore.org/en/node/284218
|
|
//! and https://musescore.org/en/node/281601
|
|
//! only needed for certain artificially emboldened fonts
|
|
//! see https://musescore.org/en/node/281601#comment-900261
|
|
//! in Qt 5.12.x this workaround should be no more necessary if
|
|
//! env variable QT_MAX_CACHED_GLYPH_SIZE is set to 1.
|
|
//! The workaround works badly if the text is at the same time
|
|
//! bold and underlined or struck out.
|
|
//! (moved from TextBase::drawTextWorkaround)
|
|
void drawTextWorkaround(Font& f, const PointF pos, const String& text);
|
|
|
|
void drawSymbol(const PointF& point, char32_t ucs4Code);
|
|
|
|
void fillRect(const RectF& rect, const Brush& brush);
|
|
|
|
void drawPixmap(const PointF& point, const Pixmap& pm);
|
|
void drawTiledPixmap(const RectF& rect, const Pixmap& pm, const PointF& offset = PointF());
|
|
|
|
#ifndef NO_QT_SUPPORT
|
|
void drawPixmap(const PointF& point, const QPixmap& pm);
|
|
void drawTiledPixmap(const RectF& rect, const QPixmap& pm, const PointF& offset = PointF());
|
|
#endif
|
|
|
|
void setClipRect(const RectF& rect);
|
|
void setClipping(bool enable);
|
|
|
|
//! NOTE Provider for tests.
|
|
//! We're not ready to use DI (ModuleIoC) here yet
|
|
static IPaintProviderPtr extended;
|
|
|
|
private:
|
|
|
|
struct State {
|
|
RectF window;
|
|
RectF viewport;
|
|
bool isVxF = false;
|
|
Transform viewTransform;
|
|
bool isWxF = false;
|
|
Transform worldTransform; // World transformation matrix, not window and viewport
|
|
Transform transform; // Complete transformation matrix
|
|
};
|
|
|
|
void init();
|
|
State& editableState();
|
|
const State& state() const;
|
|
void updateViewTransform();
|
|
void updateMatrix();
|
|
|
|
bool endTarget(bool endDraw);
|
|
|
|
IPaintProviderPtr m_provider;
|
|
std::string m_name;
|
|
std::stack<State> m_states;
|
|
};
|
|
|
|
inline void Painter::setPen(const Color& color)
|
|
{
|
|
setPen(Pen(color.isValid() ? color : Color::BLACK));
|
|
}
|
|
|
|
inline void Painter::translate(const PointF& offset)
|
|
{
|
|
translate(offset.x(), offset.y());
|
|
}
|
|
|
|
inline void Painter::drawLine(const LineF& l)
|
|
{
|
|
drawLines(&l, 1);
|
|
}
|
|
|
|
inline void Painter::drawLine(const PointF& p1, const PointF& p2)
|
|
{
|
|
drawLine(LineF(p1, p2));
|
|
}
|
|
|
|
inline void Painter::drawLine(int x1, int y1, int x2, int y2)
|
|
{
|
|
LineF l(PointF(x1, y1), PointF(x2, y2));
|
|
drawLines(&l, 1);
|
|
}
|
|
|
|
inline void Painter::drawLines(const std::vector<LineF>& lines)
|
|
{
|
|
drawLines(lines.data(), lines.size());
|
|
}
|
|
|
|
inline void Painter::drawRect(const RectF& rect)
|
|
{
|
|
drawRects(&rect, 1);
|
|
}
|
|
|
|
inline void Painter::drawRect(int x, int y, int w, int h)
|
|
{
|
|
RectF r(x, y, w, h);
|
|
drawRects(&r, 1);
|
|
}
|
|
|
|
inline void Painter::drawEllipse(const PointF& center, double rx, double ry)
|
|
{
|
|
drawEllipse(RectF(center.x() - rx, center.y() - ry, 2 * rx, 2 * ry));
|
|
}
|
|
|
|
inline void Painter::drawPolyline(const PolygonF& polyline)
|
|
{
|
|
drawPolyline(polyline.data(), polyline.size());
|
|
}
|
|
|
|
inline void Painter::drawPolygon(const PolygonF& polygon, FillRule fillRule)
|
|
{
|
|
drawPolygon(polygon.data(), polygon.size(), fillRule);
|
|
}
|
|
|
|
inline void Painter::drawConvexPolygon(const PolygonF& poly)
|
|
{
|
|
drawConvexPolygon(poly.data(), poly.size());
|
|
}
|
|
|
|
inline void Painter::drawText(int x, int y, const String& text)
|
|
{
|
|
drawText(PointF(x, y), text);
|
|
}
|
|
|
|
class PainterObjMarker
|
|
{
|
|
public:
|
|
PainterObjMarker(Painter* p, const std::string& name, const PointF& objPagePos)
|
|
: m_painter(p)
|
|
{
|
|
p->beginObject(name, objPagePos);
|
|
}
|
|
|
|
~PainterObjMarker()
|
|
{
|
|
m_painter->endObject();
|
|
}
|
|
|
|
private:
|
|
Painter* m_painter = nullptr;
|
|
};
|
|
|
|
#ifdef MUE_ENABLE_DRAW_TRACE
|
|
#define TRACE_OBJ_DRAW \
|
|
mu::draw::PainterObjMarker __drawObjMarker(painter, typeName(), pagePos())
|
|
|
|
#define TRACE_OBJ_DRAW_C(painter, objName, objPagePos) \
|
|
mu::draw::PainterObjMarker __drawObjMarker(painter, objName, objPagePos)
|
|
#else
|
|
#define TRACE_OBJ_DRAW
|
|
#define TRACE_OBJ_DRAW_C(painter, objName, objPagePos)
|
|
#endif
|
|
}
|
|
|
|
#endif // MU_DRAW_PAINTER_H
|