Mercurial > projects > qtd
view demos/deform/pathdeform.d @ 331:1defd6a98364 signals
Make static constructors shared. Requires new dmd. Remove irrelevant junk
author | eldar1@eldar1-laptop |
---|---|
date | Fri, 22 Jan 2010 23:59:07 +0000 |
parents | 0f23cdea249a |
children | 5bcfe9e7db7f |
line wrap: on
line source
/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** ** This file is part of the demonstration applications of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial Usage ** Licensees holding valid Qt Commercial licenses may use this file in ** accordance with the Qt Commercial License Agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain ** additional rights. These rights are described in the Nokia Qt LGPL ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this ** package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at qt-sales@nokia.com. ** $QT_END_LICENSE$ ** ****************************************************************************/ module pathdeform; import arthurwidgets, qt.gui.QPainterPath, qt.gui.QApplication, qt.gui.QMouseEvent, qt.core.QDateTime, qt.core.QTimerEvent, qt.core.QBasicTimer, qt.gui.QLayout, qt.gui.QLineEdit, qt.gui.QPainter, qt.gui.QSlider, qt.gui.QLabel, qt.gui.QDesktopWidget, qt.gui.QGroupBox, qt.gui.QPushButton, qt.gui.QVBoxLayout, qt.gui.QGridLayout, qt.gui.QHBoxLayout, qt.gui.QRadialGradient, qt.opengl.QGLFormat, tango.math.Math; class PathDeformControls : QWidget { private PathDeformRenderer m_renderer; mixin Signal!("okPressed"); mixin Signal!("quitPressed"); this(QWidget parent, PathDeformRenderer renderer, bool smallScreen) { super(parent); m_renderer = renderer; if (smallScreen) layoutForSmallScreen(); else layoutForDesktop(); } void layoutForDesktop() { QGroupBox mainGroup = new QGroupBox(this); mainGroup.setTitle(tr("Controls")); QGroupBox radiusGroup = new QGroupBox(mainGroup); radiusGroup.setTitle(tr("Lens Radius")); QSlider radiusSlider = new QSlider(Qt.Horizontal, radiusGroup); radiusSlider.setRange(15, 150); radiusSlider.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed); QGroupBox deformGroup = new QGroupBox(mainGroup); deformGroup.setTitle(tr("Deformation")); QSlider deformSlider = new QSlider(Qt.Horizontal, deformGroup); deformSlider.setRange(-100, 100); deformSlider.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed); QGroupBox fontSizeGroup = new QGroupBox(mainGroup); fontSizeGroup.setTitle(tr("Font Size")); QSlider fontSizeSlider = new QSlider(Qt.Horizontal, fontSizeGroup); fontSizeSlider.setRange(16, 200); fontSizeSlider.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed); QGroupBox textGroup = new QGroupBox(mainGroup); textGroup.setTitle(tr("Text")); QLineEdit textInput = new QLineEdit(textGroup); QPushButton animateButton = new QPushButton(mainGroup); animateButton.setText(tr("Animated")); animateButton.setCheckable(true); QPushButton showSourceButton = new QPushButton(mainGroup); showSourceButton.setText(tr("Show Source")); version (QT_OPENGL_SUPPORT) { QPushButton enableOpenGLButton = new QPushButton(mainGroup); enableOpenGLButton.setText(tr("Use OpenGL")); enableOpenGLButton.setCheckable(true); enableOpenGLButton.setChecked(m_renderer.usesOpenGL()); if (!QGLFormat.hasOpenGL()) enableOpenGLButton.hide(); } QPushButton whatsThisButton = new QPushButton(mainGroup); whatsThisButton.setText(tr("What's This?")); whatsThisButton.setCheckable(true); mainGroup.setFixedWidth(180); QVBoxLayout mainGroupLayout = new QVBoxLayout(mainGroup); mainGroupLayout.addWidget(radiusGroup); mainGroupLayout.addWidget(deformGroup); mainGroupLayout.addWidget(fontSizeGroup); mainGroupLayout.addWidget(textGroup); mainGroupLayout.addWidget(animateButton); mainGroupLayout.addStretch(1); version (QT_OPENGL_SUPPORT) { mainGroupLayout.addWidget(enableOpenGLButton); } mainGroupLayout.addWidget(showSourceButton); mainGroupLayout.addWidget(whatsThisButton); QVBoxLayout radiusGroupLayout = new QVBoxLayout(radiusGroup); radiusGroupLayout.addWidget(radiusSlider); QVBoxLayout deformGroupLayout = new QVBoxLayout(deformGroup); deformGroupLayout.addWidget(deformSlider); QVBoxLayout fontSizeGroupLayout = new QVBoxLayout(fontSizeGroup); fontSizeGroupLayout.addWidget(fontSizeSlider); QVBoxLayout textGroupLayout = new QVBoxLayout(textGroup); textGroupLayout.addWidget(textInput); QVBoxLayout mainLayout = new QVBoxLayout(this); mainLayout.addWidget(mainGroup); mainLayout.setMargin(0); radiusSlider.valueChanged.connect(&m_renderer.setRadius); deformSlider.valueChanged.connect(&m_renderer.setIntensity); fontSizeSlider.valueChanged.connect(&m_renderer.setFontSize); animateButton.clicked.connect(&m_renderer.setAnimated); version (QT_OPENGL_SUPPORT) { enableOpenGLButton.clicked.connect(&m_renderer.enableOpenGL); } textInput.textChanged.connect(&m_renderer.setText); m_renderer.descriptionEnabledChanged.connect(&whatsThisButton.setChecked); whatsThisButton.clicked.connect(&m_renderer.setDescriptionEnabled); showSourceButton.clicked.connect(&m_renderer.showSource); animateButton.animateClick(); deformSlider.setValue(80); fontSizeSlider.setValue(120); radiusSlider.setValue(100); textInput.setText(tr("Qt")); } void layoutForSmallScreen() { QGroupBox mainGroup = new QGroupBox(this); mainGroup.setTitle(tr("Controls")); QLabel radiusLabel = new QLabel(mainGroup); radiusLabel.setText(tr("Lens Radius:")); QSlider radiusSlider = new QSlider(Qt.Horizontal, mainGroup); radiusSlider.setRange(15, 150); radiusSlider.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed); QLabel deformLabel = new QLabel(mainGroup); deformLabel.setText(tr("Deformation:")); QSlider deformSlider = new QSlider(Qt.Horizontal, mainGroup); deformSlider.setRange(-100, 100); deformSlider.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed); QLabel fontSizeLabel = new QLabel(mainGroup); fontSizeLabel.setText(tr("Font Size:")); QSlider fontSizeSlider = new QSlider(Qt.Horizontal, mainGroup); fontSizeSlider.setRange(16, 200); fontSizeSlider.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed); QPushButton animateButton = new QPushButton(tr("Animated"), mainGroup); animateButton.setCheckable(true); version (QT_OPENGL_SUPPORT) { QPushButton enableOpenGLButton = new QPushButton(mainGroup); enableOpenGLButton.setText(tr("Use OpenGL")); enableOpenGLButton.setCheckable(true); enableOpenGLButton.setChecked(m_renderer.usesOpenGL()); if (!QGLFormat.hasOpenGL()) enableOpenGLButton.hide(); } QPushButton quitButton = new QPushButton(tr("Quit"), mainGroup); QPushButton okButton = new QPushButton(tr("OK"), mainGroup); QGridLayout mainGroupLayout = new QGridLayout(mainGroup); mainGroupLayout.setMargin(0); mainGroupLayout.addWidget(radiusLabel, 0, 0, Qt.AlignRight); mainGroupLayout.addWidget(radiusSlider, 0, 1); mainGroupLayout.addWidget(deformLabel, 1, 0, Qt.AlignRight); mainGroupLayout.addWidget(deformSlider, 1, 1); mainGroupLayout.addWidget(fontSizeLabel, 2, 0, Qt.AlignRight); mainGroupLayout.addWidget(fontSizeSlider, 2, 1); mainGroupLayout.addWidget(animateButton, 3,0, 1,2); version (QT_OPENGL_SUPPORT) { mainGroupLayout.addWidget(enableOpenGLButton, 4,0, 1,2); } QVBoxLayout mainLayout = new QVBoxLayout(this); mainLayout.addWidget(mainGroup); mainLayout.addStretch(1); mainLayout.addWidget(okButton); mainLayout.addWidget(quitButton); quitButton.clicked.connect(&emitQuitSignal); okButton.clicked.connect(&emitOkSignal); radiusSlider.valueChanged.connect(&m_renderer.setRadius); deformSlider.valueChanged.connect(&m_renderer.setIntensity); fontSizeSlider.valueChanged.connect(&m_renderer.setFontSize); animateButton.clicked.connect(&m_renderer.setAnimated); version (QT_OPENGL_SUPPORT) { enableOpenGLButton.clicked.connect(&m_renderer.enableOpenGL); } animateButton.animateClick(); deformSlider.setValue(80); fontSizeSlider.setValue(120); QRect screen_size = QApplication.desktop().screenGeometry(); radiusSlider.setValue(qMin(screen_size.width(), screen_size.height())/5); m_renderer.setText(tr("Qt")); } void emitQuitSignal() { quitPressed.emit; } void emitOkSignal() { okPressed.emit; } } class PathDeformWidget : QWidget { private: PathDeformRenderer m_renderer; PathDeformControls m_controls; public: this(QWidget parent, bool smallScreen) { super(parent); setWindowTitle(tr("Vector Deformation")); m_renderer = new PathDeformRenderer(this, smallScreen); m_renderer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding); // Layouts QHBoxLayout mainLayout = new QHBoxLayout(this); mainLayout.addWidget(m_renderer); m_controls = new PathDeformControls(null, m_renderer, smallScreen); m_controls.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Minimum); if (!smallScreen) mainLayout.addWidget(m_controls); m_renderer.loadSourceFile(":res/deform/pathdeform.d"); m_renderer.loadDescription(":res/deform/pathdeform.html"); m_renderer.setDescriptionEnabled(false); m_renderer.clicked.connect(&showControls); m_controls.okPressed.connect(&hideControls); m_controls.quitPressed.connect(&QApplication.quit); } void showControls() { m_controls.showFullScreen; } void hideControls() { m_controls.hide; } void setWidgetStyle(QStyle style) // TODO: QWidget.setStyle is not virtual { super.setStyle(style); if (m_controls) { m_controls.setStyle(style); QWidget[] widgets = m_controls.findChildren!(QWidget); foreach (w; widgets) w.setStyle(style); } } } private QRect circle_bounds(QPointF center, qreal radius, qreal compensation) { return QRect(qRound(center.x() - radius - compensation), qRound(center.y() - radius - compensation), qRound((radius + compensation) * 2), qRound((radius + compensation) * 2)); } enum { LENS_EXTENT = 10 } class PathDeformRenderer : ArthurFrame { private: QBasicTimer m_repaintTimer; // QBasicTimer m_fpsTimer; // int m_fpsCounter; QTime m_repaintTracker; QPainterPath[] m_paths; QPointF[] m_advances; QRectF m_pathBounds; string m_text; QPixmap m_lens_pixmap; QImage m_lens_image; int m_fontSize; bool m_animated; qreal m_intensity; qreal m_radius; QPointF m_pos; QPointF m_offset; QPointF m_direction; QPointF m_mousePress; bool m_mouseDrag; bool m_smallScreen; public: mixin Signal!("clicked"); this(QWidget widget, bool smallScreen) { super(widget); m_radius = 100; m_pos = QPointF(m_radius, m_radius); m_direction = QPointF(1, 1); m_fontSize = 24; m_animated = true; m_repaintTimer.start(25, this); m_repaintTracker.start(); m_intensity = 100; m_smallScreen = smallScreen; // m_fpsTimer.start(1000, this); // m_fpsCounter = 0; generateLensPixmap(); } void setFontSize(int fontSize) { m_fontSize = fontSize; setText(m_text); } override QSize sizeHint() { return QSize(600, 500); } bool animated() { return m_animated; } int radius() { return cast(int) m_radius; } int fontSize() { return m_fontSize; } int intensity() { return cast(int) m_intensity; } string text() { return m_text; } void setText(string text) { m_text = text; auto f = new QFont("times new roman,utopia"); f.setStyleStrategy(QFont.ForceOutline); f.setPointSize(m_fontSize); f.setStyleHint(QFont.Times); m_paths = null; m_pathBounds = QRectF(); QPointF advance; bool do_quick = true; for (int i = 0; i < text.length; ++i) { if (text[i].unicode() >= 0x4ff && text.at(i).unicode() <= 0x1e00) { do_quick = false; break; } } if (do_quick) { for (int i = 0; i < text.length; ++i) { QPainterPath path = new QPainterPath; path.addText(advance, f, text.mid(i, 1)); m_pathBounds |= path.boundingRect(); m_paths ~= path; advance += QPointF(fm.width(text.mid(i, 1)), 0); } } else { QPainterPath path = new QPainterPath; path.addText(advance, f, text); m_pathBounds |= path.boundingRect(); m_paths ~= path; } for (int i = 0; i < m_paths.length; ++i) m_paths[i] = m_paths[i] * (new QMatrix(1, 0, 0, 1, -m_pathBounds.x(), -m_pathBounds.y())); update(); } void generateLensPixmap() { qreal rad = m_radius + LENS_EXTENT; QRect bounds = circle_bounds(QPointF(), rad, 0); QPainter painter = new QPainter; if (preferImage()) { m_lens_image = new QImage(bounds.size(), QImage.Format_ARGB32_Premultiplied); m_lens_image.fill(0); painter.begin(m_lens_image); } else { m_lens_pixmap = new QPixmap(bounds.size()); m_lens_pixmap.fill(new QColor(Qt.transparent)); painter.begin(m_lens_pixmap); } auto gr = new QRadialGradient(rad, rad, rad, 3 * rad / 5, 3 * rad / 5); gr.setColorAt(0.0, new QColor(255, 255, 255, 191)); gr.setColorAt(0.2, new QColor(255, 255, 127, 191)); gr.setColorAt(0.9, new QColor(150, 150, 200, 63)); gr.setColorAt(0.95, new QColor(0, 0, 0, 127)); gr.setColorAt(1, new QColor(0, 0, 0, 0)); painter.setRenderHint(QPainter.Antialiasing); painter.setBrush(gr); painter.setPen(Qt.NoPen); painter.drawEllipse(0, 0, bounds.width(), bounds.height()); } void setAnimated(bool animated) { m_animated = animated; if (m_animated) { // m_fpsTimer.start(1000, this); // m_fpsCounter = 0; m_repaintTimer.start(25, this); m_repaintTracker.start(); } else { // m_fpsTimer.stop(); m_repaintTimer.stop(); } } override void timerEvent(QTimerEvent e) { if (e.timerId == m_repaintTimer.timerId) { if ((QLineF(QPointF(0,0), m_direction)).length() > 1) m_direction *= 0.995; qreal time = m_repaintTracker.restart(); QRect rectBefore = circle_bounds(m_pos, m_radius, m_fontSize); qreal dx = m_direction.x(); qreal dy = m_direction.y(); if (time > 0) { dx = dx * time * .1; dy = dy * time * .1; } m_pos += QPointF(dx, dy); if (m_pos.x() - m_radius < 0) { m_direction.x = -m_direction.x; m_pos.x = m_radius; } else if (m_pos.x + m_radius > width) { m_direction.x = -m_direction.x; m_pos.x = width - m_radius; } if (m_pos.y - m_radius < 0) { m_direction.y = -m_direction.y; m_pos.y = m_radius; } else if (m_pos.y + m_radius > height) { m_direction.y = -m_direction.y; m_pos.y = height - m_radius; } void noGLUpdate() { QRect rectAfter = circle_bounds(m_pos, m_radius, m_fontSize); update(rectAfter.united(rectBefore)); QApplication.syncX(); } version (QT_OPENGL_SUPPORT) { if (usesOpenGL()) { update; } else noGLUpdate; } else noGLUpdate; } // else if (e.timerId() == m_fpsTimer.timerId()) { // printf("fps: %d\n", m_fpsCounter); // emit frameRate(m_fpsCounter); // m_fpsCounter = 0; // } } override void mousePressEvent(QMouseEvent e) { setDescriptionEnabled(false); m_repaintTimer.stop(); m_offset = QPointF(); if ((QLineF(m_pos, QPointF(e.pos))).length <= m_radius) m_offset = m_pos - QPointF(e.pos); m_mousePress = QPointF(e.pos); // If we're not running in small screen mode, always assume we're dragging m_mouseDrag = !m_smallScreen; mouseMoveEvent(e); } override void mouseReleaseEvent(QMouseEvent e) { if (e.buttons() == Qt.NoButton && m_animated) { m_repaintTimer.start(10, this); m_repaintTracker.start(); } if (!m_mouseDrag && m_smallScreen) clicked.emit; } override void mouseMoveEvent(QMouseEvent e) { auto epos = QPointF(e.pos); if (!m_mouseDrag && (QLineF(m_mousePress, QPointF(e.pos))).length() > 25.0) m_mouseDrag = true; if (m_mouseDrag) { QRect rectBefore = circle_bounds(m_pos, m_radius, m_fontSize); if (e.type() == QEvent.MouseMove) { QLineF line = QLineF(m_pos, epos + m_offset); line.setLength(line.length() * .1); auto dir = QPointF(line.dx(), line.dy()); m_direction = (m_direction + dir) / 2; } m_pos = epos + m_offset; void noGLUpdate() { QRect rectAfter = circle_bounds(m_pos, m_radius, m_fontSize); update(rectBefore.united(rectAfter)); } version (QT_OPENGL_SUPPORT) { if (usesOpenGL()) { update; } else noGLUpdate; } else noGLUpdate; } } QPainterPath lensDeform(QPainterPath source, QPointF offset) { auto path = new QPainterPath; path.addPath(source); qreal flip = m_intensity / 100.0; for (int i=0; i<path.elementCount; ++i) { auto e = path.elementAt(i); qreal x = e.x + offset.x(); qreal y = e.y + offset.y(); qreal dx = x - m_pos.x(); qreal dy = y - m_pos.y(); qreal len = m_radius - sqrt(dx * dx + dy * dy); if (len > 0) { path.setElementPositionAt(i, x + flip * dx * len / m_radius, y + flip * dy * len / m_radius); } else { path.setElementPositionAt(i, x, y); } } return path; } override void paint(QPainter painter) { int pad_x = 5; int pad_y = 5; int skip_x = qRound(m_pathBounds.width() + pad_x + m_fontSize/2); int skip_y = qRound(m_pathBounds.height() + pad_y); painter.setPen(Qt.NoPen); painter.setBrush(new QColor(Qt.black)); auto clip = painter.clipPath().boundingRect(); int overlap = pad_x / 2; for (int start_y=0; start_y < height(); start_y += skip_y) { if (start_y > clip.bottom()) break; int start_x = -overlap; for (; start_x < width(); start_x += skip_x) { if (start_y + skip_y >= clip.top() && start_x + skip_x >= clip.left() && start_x <= clip.right()) { for (int i=0; i<m_paths.length; ++i) { QPainterPath path = lensDeform(m_paths[i], QPointF(start_x, start_y)); painter.drawPath(path); } } } overlap = skip_x - (start_x - width()); } if (preferImage) { painter.drawImage(m_pos - QPointF(m_radius + LENS_EXTENT, m_radius + LENS_EXTENT), m_lens_image); } else { painter.drawPixmap(m_pos - QPointF(m_radius + LENS_EXTENT, m_radius + LENS_EXTENT), m_lens_pixmap); } } void setRadius(int radius) { qreal max = max(m_radius, cast(qreal)radius); m_radius = radius; generateLensPixmap(); if (!m_animated || m_radius < max) { auto noGLUpdate = (){ update(circle_bounds(m_pos, max, m_fontSize)); }; version (QT_OPENGL_SUPPORT) { if (usesOpenGL()) update(); else noGLUpdate(); } else noGLUpdate(); } } void setIntensity(int intensity) { m_intensity = intensity; if (!m_animated) { auto noGLUpdate = (){ update(circle_bounds(m_pos, m_radius, m_fontSize)); }; version (QT_OPENGL_SUPPORT) { if (usesOpenGL()) { update(); } else noGLUpdate(); } else noGLUpdate(); } } }