/** * The annotation tool has fairly complex needs. Clicking on an existing * annotation selects it, otherwise a new annotation is started. */ void Annotation::begin(const paintcore::Point& point, float zoom) { m_selectedId = owner.model()->annotations()->annotationAtPos(point.toPoint(), zoom); m_p1 = point; m_p2 = point; m_isNew = m_selectedId==0; if(m_selectedId>0) { m_handle = owner.model()->annotations()->annotationHandleAt(m_selectedId, point.toPoint(), zoom); owner.setActiveAnnotation(m_selectedId); } else { // No annotation, start creating a new one // I don't want to create a new preview item just for annotations, // so we create the preview annotation directly in the model. Since this // doesn't affect the other annotations, it shouldn't case any problems. // Also, we use a special ID for the preview object that is outside the protocol range. m_selectedId = PREVIEW_ID; owner.model()->annotations()->changeAnnotation(canvas::Annotation { m_selectedId, QString(), QRect(m_p1.toPoint(), m_p1.toPoint() + QPoint(5,5)), QColor(Qt::transparent) } ); m_handle = canvas::Annotation::RS_BOTTOMRIGHT; } }
/** * Convert a dpcore::Point to network format. The * reverse operation for this is in statetracker.cpp * @param p * @return */ protocol::PenPoint pointToProtocol(const paintcore::Point &point) { int32_t x = point.x() * 4.0; int32_t y = point.y() * 4.0; uint16_t p = point.pressure() * 0xffff; return protocol::PenPoint(x, y, p); }
void ColorPicker::motion(const paintcore::Point& point, bool constrain, bool center) { Q_UNUSED(constrain); Q_UNUSED(center); int layer=0; if(settings().getColorPickerSettings()->pickFromLayer()) { layer = this->layer(); } scene().pickColor(point.x(), point.y(), layer, _bg); }
void ColorPicker::motion(const paintcore::Point& point, bool constrain, bool center) { Q_UNUSED(constrain); Q_UNUSED(center); int layer=0; if(owner.toolSettings()->getColorPickerSettings()->pickFromLayer()) { layer = owner.activeLayer(); } int size = owner.toolSettings()->getColorPickerSettings()->getSize(); owner.model()->pickColor(point.x(), point.y(), layer, size); }
void FloodFill::begin(const paintcore::Point &point, float zoom) { // TODO do this in the layer thread? Q_UNUSED(zoom); FillSettings *ts = owner.toolSettings()->getFillSettings(); QColor color = owner.toolSettings()->foregroundColor(); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); owner.model()->layerStack()->lock(); paintcore::FillResult fill = paintcore::floodfill( owner.model()->layerStack(), QPoint(point.x(), point.y()), color, ts->fillTolerance(), owner.activeLayer(), ts->sampleMerged() ); owner.model()->layerStack()->unlock(); fill = paintcore::expandFill(fill, ts->fillExpansion(), color); if(fill.image.isNull()) { QApplication::restoreOverrideCursor(); return; } // If the target area is transparent, use the BEHIND compositing mode. // This results in nice smooth blending with soft outlines, when the // outline has different color than the fill. paintcore::BlendMode::Mode mode = paintcore::BlendMode::MODE_NORMAL; if(ts->underFill() && (fill.layerSeedColor & 0xff000000) == 0) mode = paintcore::BlendMode::MODE_BEHIND; // Flood fill is implemented using PutImage rather than a native command. // This has the following advantages: // - backward and forward compatibility: changes in the algorithm can be made freely // - tolerates out-of-sync canvases (shouldn't normally happen, but...) // - bugs don't crash/freeze other clients // // The disadvantage is increased bandwith consumption. However, this is not as bad // as one might think: the effective bit-depth of the bitmap is 1bpp and most fills // consist of large solid areas, meaning they should compress ridiculously well. QList<protocol::MessagePtr> msgs; msgs << protocol::MessagePtr(new protocol::UndoPoint(0)); msgs << net::command::putQImage(0, owner.activeLayer(), fill.x, fill.y, fill.image, mode); owner.client()->sendMessages(msgs); QApplication::restoreOverrideCursor(); }
void CanvasView::onPenDown(const paintcore::Point &p, bool right) { if(_scene->hasImage() && !_locked) { if(_specialpenmode) { // quick color pick mode _scene->pickColor(p.x(), p.y(), 0, right); } else { if(_smoothing>0 && _current_tool->allowSmoothing()) _smoother.addPoint(p); else _current_tool->begin(p, right, _zoom); } } }
void CanvasView::onPenMove(const paintcore::Point &p, bool right, bool shift, bool alt) { if(_scene->hasImage() && !_locked) { if(_specialpenmode) { // quick color pick mode _scene->pickColor(p.x(), p.y(), 0, right); } else { if(_smoothing>0 && _current_tool->allowSmoothing()) { _smoother.addPoint(p); if(_smoother.hasSmoothPoint()) { if(_smoother.isFirstSmoothPoint()) _current_tool->begin(_smoother.smoothPoint(), right, _zoom); else _current_tool->motion(_smoother.smoothPoint(), shift, alt); } } else { _current_tool->motion(p, shift, alt); } } } }
void CanvasView::updateOutline(paintcore::Point point) { if(!_subpixeloutline) { point.setX(qFloor(point.x())); point.setY(qFloor(point.y())); } if(_enableoutline && _showoutline && !_locked && !point.roughlySame(_prevoutlinepoint)) { QList<QRectF> rect; rect.append(QRectF(_prevoutlinepoint.x() - _outlinesize, _prevoutlinepoint.y() - _outlinesize, _dia, _dia)); rect.append(QRectF(point.x() - _outlinesize, point.y() - _outlinesize, _dia, _dia)); updateScene(rect); _prevoutlinepoint = point; } }