![]() |
QElectroTech 0.200.1-dev
|
#include <diagramimageitem.h>


Public Types | |
| enum | { Type = UserType + 1007 } |
| enum class | HandleMode { Size , RotateSkew } |
| enum class | HandleRole { Resize , Rotate , SkewEdge , Pivot } |
Signals | |
| void | pixmapChanged () |
| void | transformChanged () |
Public Member Functions | |
| DiagramImageItem (QetGraphicsItem *=nullptr) | |
| DiagramImageItem::DiagramImageItem Constructor without pixmap. | |
| DiagramImageItem (const QPixmap &pixmap, QetGraphicsItem *=nullptr) | |
| DiagramImageItem::DiagramImageItem Constructor with pixmap. | |
| ~DiagramImageItem () override | |
| DiagramImageItem::~DiagramImageItem Destructor. | |
| int | type () const override |
| virtual bool | fromXml (const QDomElement &) |
| DiagramImageItem::fromXml Load this image from xml element e. | |
| virtual QDomElement | toXml (QDomDocument &) const |
| void | editProperty () override |
| DiagramImageItem::editProperty Open the appropriate dialog to edit this image. | |
| void | setPixmap (const QPixmap &pixmap) |
| DiagramImageItem::setPixmap Set the new pixmap to be draw. | |
| QPixmap | pixmap () const |
| QRectF | boundingRect () const override |
| DiagramImageItem::boundingRect the outer bounds of the item as a rectangle, if no pixmap are set, return a default QRectF. | |
| QString | name () const override |
| DiagramImageItem::name. | |
| void | paintForExport (QPainter *painter) |
| qreal | scaleFactorX () const |
| qreal | scaleFactorY () const |
| void | setScaleFactorX (qreal factor) |
| DiagramImageItem::setScaleFactorX / setScaleFactorY / setRotationAngle Matching QetShapeItem's own setters for the identical fields – same pattern, same reasoning: change the one field, rebuild the matrix, notify. No pivot or position compensation needed here, unlike setPivot() below, since neither scale nor rotation moves the pivot itself. | |
| void | setScaleFactorY (qreal factor) |
| qreal | rotationAngle () const |
| void | setRotationAngle (qreal angle) |
| qreal | skewX () const |
| void | setSkewX (qreal skew) |
| qreal | skewY () const |
| void | setSkewY (qreal skew) |
| QPointF | pivot () const |
| void | setPivot (const QPointF &pivot) |
| DiagramImageItem::setPivot Unlike scale/rotation, moving the pivot alone WOULD visibly shift the image on screen, since the pivot is baked directly into the transform matrix – compensatedPositionForNewPivot() (already proven correct for QetShapeItem's identical need) solves for whatever pos() keeps the image exactly where it already was, so only the handle moves, not the picture underneath it. | |
| void | setPivotRaw (const QPointF &pivot) |
| DiagramImageItem::setPivotRaw Sets m_transform.pivot directly, with NO position compensation at all – deliberately, unlike setPivot() above. Exists solely for crop()'s own undo chain (see the Q_PROPERTY declaration's comment for why): crop() already computes the fully correct pos() itself, accounting for the crop, and pushes that as its own independent undo step, so compensating pos() again here would silently corrupt it back to a wrong value the moment this step replays. Never call this expecting the image to stay visually in place on its own – it won't; the caller is responsible for that. | |
| Public Member Functions inherited from QetGraphicsItem | |
| QetGraphicsItem (QGraphicsItem *parent=nullptr) | |
| ~QetGraphicsItem () override=0 | |
| Diagram * | diagram () const |
| virtual void | setPos (const QPointF &p) |
| virtual void | setPos (qreal x, qreal y) |
| virtual bool | isMovable () const |
| virtual void | setMovable (bool movable) |
| bool | isHovered () const |
| QPointF | hoverMousePos () const |
| QET::GraphicsItemState | state () const |
| QetGraphicsItem::state. | |
Protected Member Functions | |
| void | paint (QPainter *, const QStyleOptionGraphicsItem *, QWidget *) override |
| DiagramImageItem::paint Draw the pixmap. | |
| void | contextMenuEvent (QGraphicsSceneContextMenuEvent *event) override |
| DiagramImageItem::contextMenuEvent. | |
| void | mousePressEvent (QGraphicsSceneMouseEvent *event) override |
| DiagramImageItem::mousePressEvent Clicking an already-selected image cycles its handle mode, exactly matching QetShapeItem's own established convention for the same gesture – deliberately kept consistent rather than inventing a different interaction just because this is a different class. | |
| void | hoverEnterEvent (QGraphicsSceneHoverEvent *event) override |
| DiagramImageItem::hoverEnterEvent. | |
| void | hoverLeaveEvent (QGraphicsSceneHoverEvent *event) override |
| DiagramImageItem::hoverLeaveEvent. | |
| bool | sceneEventFilter (QGraphicsItem *watched, QEvent *event) override |
| DiagramImageItem::sceneEventFilter Dispatches handle interaction events – structurally identical to QetShapeItem::sceneEventFilter(), reused as a pattern rather than shared as code, since the two classes' handle roles are different enough (no path/polygon/arc concepts here at all) that sharing the dispatcher itself would need an awkward, indirect abstraction for very little actual code saved. | |
| QVariant | itemChange (GraphicsItemChange change, const QVariant &value) override |
| DiagramImageItem::itemChange. | |
| Protected Member Functions inherited from QetGraphicsItem | |
| void | mousePressEvent (QGraphicsSceneMouseEvent *event) override |
| void | mouseDoubleClickEvent (QGraphicsSceneMouseEvent *event) override |
| void | mouseMoveEvent (QGraphicsSceneMouseEvent *event) override |
| void | mouseReleaseEvent (QGraphicsSceneMouseEvent *event) override |
| QetGraphicsItem::mouseReleaseEvent handle mouse release click. | |
| void | hoverEnterEvent (QGraphicsSceneHoverEvent *event) override |
| void | hoverMoveEvent (QGraphicsSceneHoverEvent *event) override |
| void | hoverLeaveEvent (QGraphicsSceneHoverEvent *event) override |
Protected Attributes | |
| QPixmap | pixmap_ |
| QPixmap | m_base_pixmap |
| QRect | m_crop_rect |
| QList< ImageTransparentColorDialog::PickedColor > | m_transparent_colors |
| ShapeTransform | m_transform |
| bool | m_pivotIsCustom = false |
| HandleMode | m_handleMode = HandleMode::Size |
| QVector< QetGraphicsHandlerItem * > | m_handler_vector |
| QVector< HandleRole > | m_handleRoles |
| int | m_vector_index = -1 |
| QPointF | m_original_pos |
| ShapeTransform | m_original_transform |
| bool | m_deferHandleReposition = false |
| bool | m_resizeCenterAnchored = false |
| Protected Attributes inherited from QetGraphicsItem | |
| bool | is_movable_ |
| bool | m_first_move |
| bool | snap_to_grid_ |
| QPointF | m_mouse_to_origin_movement |
| QET::GraphicsItemState | m_state = QET:: GIOK |
Properties | |
| QPixmap | pixmap |
| qreal | scaleFactorX |
| qreal | scaleFactorY |
| qreal | rotationAngle |
| qreal | skewX |
| qreal | skewY |
| QPointF | pivot |
| QPointF | rawPivot |
Private Member Functions | |
| void | replaceImage () |
| DiagramImageItem::replaceImage Context-menu action: swaps the underlying pixmap for one loaded from a new file, keeping position, rotation and scale untouched – only pixmap_ changes, everything else about how this item sits on the diagram is left exactly as it was. Reuses the same file dialog filter and error handling as DiagramEventAddImage::openDialog(), so picking a replacement looks and behaves like picking a new image did when this item was first inserted. | |
| void | mirror (bool horizontal) |
| DiagramImageItem::mirror Context-menu action: flips the pixmap itself, not a transform – unlike QetShapeItem::mirror(), which has rotation/skew to contend with, there's no equivalent linear-transform decomposition needed here: the bitmap is flipped once, directly, and stays flipped regardless of whatever rotation is applied on top afterward. | |
| void | setTransparentColor () |
| DiagramImageItem::setTransparentColor Context-menu action: opens ImageTransparentColorDialog against m_base_pixmap (the pristine source), pre-populated with whatever colours and tolerance were remembered from a previous session – both problems fixed together, since they had the same root cause: passing pixmap_ (the already colour-keyed result) as if it were the source, with nowhere to remember which colours produced it. Applies the result the same way replaceImage() and mirror() do, through the "pixmap" property, so undo/redo stays consistent across all three; m_base_pixmap itself is deliberately left untouched here, since this action only ever changes which colours are keyed out of it, not the source those colours are keyed out of. | |
| void | crop () |
| DiagramImageItem::crop Context-menu action: opens ImageCropDialog against pixmap_ (the current, already colour-keyed display, so cropping is WYSIWYG against whatever is actually visible), then applies the chosen rectangle to both pixmap_ and m_base_pixmap together – kept in sync the same way mirror() keeps them in sync, since cropping is a permanent, geometric change to the image's own content, unlike setTransparentColor()'s non-destructive colour keying. | |
| void | restoreAspectRatio () |
| DiagramImageItem::restoreAspectRatio Context-menu action, the direct answer to "restoration of aspect
ratio" from the original wishlist: makes scaleY match scaleX, keeping the current width fixed. The natural aspect ratio is already fully accounted for by the pixmap's own width/height (a uniform scale, by definition, can never distort it) – the distortion is entirely scaleX and scaleY disagreeing with each other, so undoing it is exactly "make them agree", not a computation involving pixmap_'s own dimensions at all. An earlier version of this multiplied by the natural height/width ratio a second time, which double-counted it and left the image still visibly distorted, just less obviously so. | |
| void | saveImageAs () |
| DiagramImageItem::saveImageAs Saves the currently displayed pixmap (crop and colour-keyed transparency already applied – what the item actually looks like on the diagram, not the pristine original) to an arbitrary file on disk. | |
| void | saveOriginalImageAs () |
| DiagramImageItem::saveOriginalImageAs Saves m_base_pixmap – the true, pristine original, before any crop or colour-keyed transparency – rather than the item's current, possibly-cropped-and-keyed display pixmap. The only way to recover the un-cropped, un-keyed source once either of those has actually been applied, short of undoing every edit back to the point it was first inserted or replaced. | |
| void | saveImagePixmapAs (const QPixmap &pixmap, const QString &dialogTitle, bool hasTransparency) |
| DiagramImageItem::saveImagePixmapAs Shared by saveImageAs() and saveOriginalImageAs(): prompts for a destination, resolves whichever format was actually intended, warns before silently dropping transparency, and writes the file. A read-only export, not an edit: doesn't touch diagram()'s undo stack, and works even on a read-only diagram, unlike every other action in this item's context menu. | |
| void | toggleHandleMode () |
| DiagramImageItem::toggleHandleMode. | |
| HandleMode | nextHandleMode () const |
| DiagramImageItem::nextHandleMode. | |
| void | updateModeHint () |
| DiagramImageItem::updateModeHint Keeps the tooltip in sync with what the next click would do – called on selection change (so it appears/disappears with the handles themselves) and after every mode switch. Ported from QetShapeItem's identical method: deliberately short, since this is a tooltip, not documentation – the fuller gesture/modifier reference lives in the status bar instead (see currentModeStatusHint(), hoverEnterEvent()). | |
| void | refreshInteractionHints () |
| DiagramImageItem::refreshInteractionHints Keeps the tooltip text current, and – if already being hovered – immediately re-shows both the tooltip and the status bar hint rather than leaving them stuck on whatever was true before. Ported from QetShapeItem's identical method, for the identical reason: Qt only re-evaluates a tooltip, and this class only re-shows the status bar, when the cursor moves – selecting an image (often clicked while the mouse was already sitting on it) or cycling handle modes (definitely clicked while sitting on it) both change what should be shown without the cursor moving at all. | |
| QString | currentModeStatusHint () const |
| DiagramImageItem::currentModeStatusHint One-line reference for whatever handles are visible right now, shown in the status bar while hovering a selected image's body – the modifier keys in particular (Ctrl, Shift) have no other visible indication that they do anything at all. Also carries the same "next mode" information as the tooltip, since the status bar has room for the full picture in one place. | |
| void | rebuildHandles () |
| void | repositionHandles () |
| DiagramImageItem::repositionHandles Moves the existing handle items to match current geometry, without touching their identity – safe to call on every frame of a live drag, matching QetShapeItem's own repositionHandles()/rebuildHandles() split for the identical reason. | |
| void | clearHandles () |
| DiagramImageItem::clearHandles. | |
| void | resetPivotToBoundingRectCenter () |
| DiagramImageItem::resetPivotToBoundingRectCenter Used after a resize drag ends (see handlerMouseReleaseEvent()) – NOT after crop() or replaceImage(), which each compute their own, more specific position handling instead (see setPixmap()'s comment for why a single generic rule doesn't fit both of those). | |
| void | handlerMousePressEvent (int index, Qt::KeyboardModifiers mods) |
| DiagramImageItem::handlerMousePressEvent For a Resize handle, temporarily repositions the pivot for the duration of this drag: to the OPPOSITE corner/edge by default (so that one stays fixed, the usual convention), or to the CENTER if Ctrl is held at the moment of the press (so the image grows symmetrically from its middle instead). Decided once here, not re-checked on every subsequent move – mirroring the identical fix already made for shape creation, and for the identical reason: continuously re-checking made releasing the modifier mid-drag revert a decision that felt already made, rather than a deliberate choice made once at the start. | |
| void | handlerMouseMoveEvent (int index, QGraphicsSceneMouseEvent *event) |
| DiagramImageItem::handlerMouseMoveEvent. | |
| void | handlerMouseReleaseEvent (int index) |
| DiagramImageItem::handlerMouseReleaseEvent Two responsibilities, in order: first, Resize's own pivot cleanup (the pivot was temporarily relocated to the opposite corner or center in handlerMousePressEvent() purely to make the drag math simple, and has to move back now that the drag is over, via resetPivotToBoundingRectCenter(), which itself handles the position compensation that reset needs) – but only when the pivot isn't user-customized, matching dragPivot()'s own comment for why. Second – and previously entirely missing – building the actual undo command for whatever changed during this drag: every drag method above mutates m_transform directly and calls setTransform() immediately, live, with no undo tracking of its own at all, exactly like QetShapeItem's identical handlerMouseMoveEvent()/dragResize() pair. QetShapeItem's own handlerMouseReleaseEvent() is where that gets reconciled into a single undo step per role, comparing m_original_transform/m_original_pos (captured at press time) against the now-already-applied live values – this is a direct port of that same pattern for this class's own, smaller role set. Pushing a command whose redo() sets a property to what it's already live at is intentional, not wasted: redo() runs once immediately, as a harmless no-op, so the stack has a correct entry for Ctrl+Z without the live drag needing any awareness of undo at all. For Pivot specifically, chaining "pos" before "rawPivot" – not the compensating "pivot" – means undoing simply restores both to their exact recorded values, without a second, redundant compensation needing to run and (correctly, but confusingly) arrive at the same place a longer way around. | |
| void | dragResize (int index, const QPointF &localPos, Qt::KeyboardModifiers mods) |
| DiagramImageItem::dragResize Verified numerically (all 8 handles, a rotated and non-uniformly scaled starting transform) before writing this: undoing only rotation from the target – never scale, since that's the very value being solved for – is what avoids the feedback-loop mistake a full mapFromScene()-based solve would fall into (mapFromScene() divides out the CURRENT scale, not the new one, since it doesn't know a new one is being computed at all). | |
| void | dragRotateHandle (int cornerIndex, const QPointF &scenePos, Qt::KeyboardModifiers mods) |
| DiagramImageItem::dragRotateHandle Verified numerically before writing this (all 4 corners, WITH nonzero skew already present – scaleAndShearOffset() is what makes the reference direction correctly account for that): the handle ends up pointing exactly at the mouse's angle from the pivot, and the pivot itself never moves. Ported from QetShapeItem::dragRotateHandle() – see that copy's own comment for why this is a plain assignment rather than a recurrence (computing the angle via mapFromScene() would divide out the current rotation and turn each frame's result into a feedback loop). | |
| void | dragSkewHandle (int edgeIndex, const QPointF &scenePos, Qt::KeyboardModifiers mods) |
| DiagramImageItem::dragSkewHandle Verified numerically before writing this (all 4 edges, WITH nonzero rotation already present): recovers the exact skew angle that would put the edge handle at a given scene position, for both skewX (N/S edges) and skewY (E/W edges). Ported from QetShapeItem::dragSkewHandle() – see that copy's own comment for the closed-form derivation (solved for the one skew component being dragged, holding everything else fixed, since going through mapFromScene() would divide out the very value being solved for). | |
| void | dragPivot (const QPointF &localPos) |
| DiagramImageItem::dragPivot Marks the pivot as user-customized, the same way QetShapeItem's own pivot handle does – so a later resize (see handlerMouseReleaseEvent()) doesn't silently snap it back to the bounding-rect center the instant the user deliberately moved it somewhere else. | |
| QPointF | scaleOnlyOffset (const QPointF &localPoint) const |
| DiagramImageItem::scaleOnlyOffset / scaleAndShearOffset Verbatim ports of QetShapeItem's own identically-named helpers (see their definitions there for the derivation) – the offset of a local point from the pivot, with scale (and, for the second, shear too) applied but rotation deliberately left out. Used by dragRotateHandle()/dragSkewHandle() to solve for rotation/skew directly rather than through mapFromScene(), which would divide out the very value being solved for. | |
| QPointF | scaleAndShearOffset (const QPointF &localPoint) const |
| QPointF | handlePosition (int index) const |
| DiagramImageItem::handlePosition Local-space position of handle at vector index index, for whichever role it currently holds – the single source both rebuildHandles() and repositionHandles() read from, so the two can never disagree about where a handle belongs. | |
| void | showStatusHint (const QString &text) const |
| DiagramImageItem::showStatusHint. | |
| void | clearStatusHint () const |
| DiagramImageItem::clearStatusHint. | |
Static Private Member Functions | |
| static bool | writeRasterAsSvg (const QPixmap &pixmap, const QString &path) |
| DiagramImageItem::writeRasterAsSvg Wraps pixmap as a base64-embedded PNG inside a minimal, valid SVG document – the closest this can honestly offer to "save as SVG" given this item only ever holds raster data (see the note in saveImagePixmapAs()). Opens in any SVG viewer at the pixmap's own pixel size, but is not, and cannot be, a vector re-export. | |
| static QPixmap | computeDisplayPixmap (const QPixmap &base, const QRect &cropRect, const QList< ImageTransparentColorDialog::PickedColor > &colors) |
| DiagramImageItem::computeDisplayPixmap Re-derives what pixmap_ should be from first principles: crop the true original down to the chosen region, then colour-key whichever colours have been picked out of it, each at its own tolerance. Used whenever crop() or setTransparentColor() changes one of those two independently, so the other's effect is correctly re-applied on top rather than lost or compounded – cropping after colours were already picked has to still show them keyed out; picking colours after a crop has to only ever consider what's still actually part of the image. | |
| static QString | handleModeLabel (HandleMode mode) |
| DiagramImageItem::handleModeLabel. | |
| static QPointF | cornerPosition (int cornerIndex, qreal w, qreal h) |
| DiagramImageItem::cornerPosition Matches QetShapeItem::cornerPoint()'s own slot convention exactly (0=TL 1=TR 2=BR 3=BL), so the rotate math ported from there (see dragRotateHandle()) lines up without needing its own re-derivation. | |
| static QPointF | edgeMidpointPosition (int edgeIndex, qreal w, qreal h) |
| DiagramImageItem::edgeMidpointPosition Matches QetShapeItem::edgeMidpoint()'s own slot convention exactly (0=N 1=E 2=S 3=W), for the same reason as cornerPosition() above. | |
| static QColor | colorForHandleRole (HandleRole role) |
| DiagramImageItem::rebuildHandles A deliberately small switch compared to QetShapeItem's own version: images have exactly one "shape" (a plain rectangle matching the pixmap's natural size), so there's no shape-type branching to do – just the two handle modes themselves. | |
| static QString | hintForHandleRole (HandleRole role) |
Additional Inherited Members | |
| Static Public Member Functions inherited from QetGraphicsItem | |
| static void | showItem (QetGraphicsItem *item) |
| QetGraphicsItem::QetGraphicsItem Default constructor. | |
This class represents a selectable, movable and editable image on a diagram.
|
strong |
|
strong |
| DiagramImageItem::DiagramImageItem | ( | QetGraphicsItem * | parent_item = nullptr | ) |
DiagramImageItem::DiagramImageItem Constructor without pixmap.
| parent_item | the parent graphics item |

| DiagramImageItem::DiagramImageItem | ( | const QPixmap & | pixmap, |
| QetGraphicsItem * | parent_item = nullptr ) |
DiagramImageItem::DiagramImageItem Constructor with pixmap.
| pixmap | the pixmap to be draw |
| parent_item | the parent graphic item |

|
override |
DiagramImageItem::~DiagramImageItem Destructor.
|
override |
DiagramImageItem::boundingRect the outer bounds of the item as a rectangle, if no pixmap are set, return a default QRectF.

|
private |
|
private |
DiagramImageItem::clearStatusHint.


|
staticprivate |
DiagramImageItem::rebuildHandles A deliberately small switch compared to QetShapeItem's own version: images have exactly one "shape" (a plain rectangle matching the pixmap's natural size), so there's no shape-type branching to do – just the two handle modes themselves.
DiagramImageItem::colorForHandleRole / hintForHandleRole Single source of truth for both rebuildHandles() (which sets each handle's native tooltip) and sceneEventFilter()'s hover dispatch (which shows the identical text in the status bar) – keeping these as two independently-maintained copies is exactly how they'd quietly drift apart over time, as already happened once between writing this pair.

|
staticprivate |
DiagramImageItem::computeDisplayPixmap Re-derives what pixmap_ should be from first principles: crop the true original down to the chosen region, then colour-key whichever colours have been picked out of it, each at its own tolerance. Used whenever crop() or setTransparentColor() changes one of those two independently, so the other's effect is correctly re-applied on top rather than lost or compounded – cropping after colours were already picked has to still show them keyed out; picking colours after a crop has to only ever consider what's still actually part of the image.
| base | the true, uncropped original |
| cropRect | the region of base to keep, in base's own coordinates |
| colors | colours (each with its own tolerance) to key transparent within the cropped region |


|
overrideprotected |
|
staticprivate |
DiagramImageItem::cornerPosition Matches QetShapeItem::cornerPoint()'s own slot convention exactly (0=TL 1=TR 2=BR 3=BL), so the rotate math ported from there (see dragRotateHandle()) lines up without needing its own re-derivation.

|
private |
DiagramImageItem::crop Context-menu action: opens ImageCropDialog against pixmap_ (the current, already colour-keyed display, so cropping is WYSIWYG against whatever is actually visible), then applies the chosen rectangle to both pixmap_ and m_base_pixmap together – kept in sync the same way mirror() keeps them in sync, since cropping is a permanent, geometric change to the image's own content, unlike setTransparentColor()'s non-destructive colour keying.
pos() also needs adjusting, not just pixmap_: setPixmap() (called via the "pixmap" undo command below) recomputes transformOriginPoint() from the new, smaller boundingRect(), but pos() itself is untouched by that – without fixing it up here too, the surviving content would visually jump to wherever local (0,0) happens to land after shrinking, rather than staying exactly where it already was. Chained into one undo step together with the pixmap change, since undoing a crop has to restore both, or the restored (larger) image ends up in the wrong place.
DiagramImageItem::crop Context-menu action: opens ImageCropDialog against m_base_pixmap (the true, uncropped original), pre-populated with whatever crop rectangle was chosen in a previous session – re-editable, not destructive: nothing about the original content is ever discarded, only which region of it is currently being shown, exactly the same principle setTransparentColor() already follows for its own choices. Recomputes pixmap_ via computeDisplayPixmap() so any already-picked transparent colours are correctly re-applied to the newly-cropped region, rather than lost (the crop dialog itself knows nothing about them).
pos() also needs adjusting, not just pixmap_: setPixmap() (called via the "pixmap" undo command below) recomputes transformOriginPoint() from the new boundingRect(), but pos() itself is untouched by that – without fixing it up here too, the surviving content would visually jump to wherever local (0,0) ends up after the crop rect changes, rather than staying exactly where it already was. This has to work whether this is the first crop ever applied or an adjustment of an existing one, so the position math is always done relative to the CURRENT crop rect (m_crop_rect, before it's updated below) – when there's no previous crop, that's simply the whole base, which is what the very first version of this method assumed unconditionally.
Chained into one undo step together with the pixmap change, since undoing a crop has to restore both, or the restored (larger) image ends up in the wrong place.


|
private |
DiagramImageItem::currentModeStatusHint One-line reference for whatever handles are visible right now, shown in the status bar while hovering a selected image's body – the modifier keys in particular (Ctrl, Shift) have no other visible indication that they do anything at all. Also carries the same "next mode" information as the tooltip, since the status bar has room for the full picture in one place.


|
private |
DiagramImageItem::dragPivot Marks the pivot as user-customized, the same way QetShapeItem's own pivot handle does – so a later resize (see handlerMouseReleaseEvent()) doesn't silently snap it back to the bounding-rect center the instant the user deliberately moved it somewhere else.


|
private |
DiagramImageItem::dragResize Verified numerically (all 8 handles, a rotated and non-uniformly scaled starting transform) before writing this: undoing only rotation from the target – never scale, since that's the very value being solved for – is what avoids the feedback-loop mistake a full mapFromScene()-based solve would fall into (mapFromScene() divides out the CURRENT scale, not the new one, since it doesn't know a new one is being computed at all).


|
private |
DiagramImageItem::dragRotateHandle Verified numerically before writing this (all 4 corners, WITH nonzero skew already present – scaleAndShearOffset() is what makes the reference direction correctly account for that): the handle ends up pointing exactly at the mouse's angle from the pivot, and the pivot itself never moves. Ported from QetShapeItem::dragRotateHandle() – see that copy's own comment for why this is a plain assignment rather than a recurrence (computing the angle via mapFromScene() would divide out the current rotation and turn each frame's result into a feedback loop).


|
private |
DiagramImageItem::dragSkewHandle Verified numerically before writing this (all 4 edges, WITH nonzero rotation already present): recovers the exact skew angle that would put the edge handle at a given scene position, for both skewX (N/S edges) and skewY (E/W edges). Ported from QetShapeItem::dragSkewHandle() – see that copy's own comment for the closed-form derivation (solved for the one skew component being dragged, holding everything else fixed, since going through mapFromScene() would divide out the very value being solved for).


|
staticprivate |
DiagramImageItem::edgeMidpointPosition Matches QetShapeItem::edgeMidpoint()'s own slot convention exactly (0=N 1=E 2=S 3=W), for the same reason as cornerPosition() above.

|
overridevirtual |
DiagramImageItem::editProperty Open the appropriate dialog to edit this image.
Reimplemented from QetGraphicsItem.

|
virtual |
DiagramImageItem::fromXml Load this image from xml element e.
| e |

|
staticprivate |
|
private |
DiagramImageItem::handlePosition Local-space position of handle at vector index index, for whichever role it currently holds – the single source both rebuildHandles() and repositionHandles() read from, so the two can never disagree about where a handle belongs.


|
private |
DiagramImageItem::handlerMouseMoveEvent.


|
private |
DiagramImageItem::handlerMousePressEvent For a Resize handle, temporarily repositions the pivot for the duration of this drag: to the OPPOSITE corner/edge by default (so that one stays fixed, the usual convention), or to the CENTER if Ctrl is held at the moment of the press (so the image grows symmetrically from its middle instead). Decided once here, not re-checked on every subsequent move – mirroring the identical fix already made for shape creation, and for the identical reason: continuously re-checking made releasing the modifier mid-drag revert a decision that felt already made, rather than a deliberate choice made once at the start.
Verified numerically before relying on this: with the pivot fixed at whichever reference point applies, solving for a new scale that puts the dragged handle at the mouse automatically keeps that reference point exactly where it was, with zero drift, across all 8 handles and a rotated, non-uniformly-scaled starting transform. compensatedPositionForNewPivot() is what keeps this repositioning itself invisible – without it, temporarily moving the pivot would visibly jump the image the instant the drag starts.


|
private |
DiagramImageItem::handlerMouseReleaseEvent Two responsibilities, in order: first, Resize's own pivot cleanup (the pivot was temporarily relocated to the opposite corner or center in handlerMousePressEvent() purely to make the drag math simple, and has to move back now that the drag is over, via resetPivotToBoundingRectCenter(), which itself handles the position compensation that reset needs) – but only when the pivot isn't user-customized, matching dragPivot()'s own comment for why. Second – and previously entirely missing – building the actual undo command for whatever changed during this drag: every drag method above mutates m_transform directly and calls setTransform() immediately, live, with no undo tracking of its own at all, exactly like QetShapeItem's identical handlerMouseMoveEvent()/dragResize() pair. QetShapeItem's own handlerMouseReleaseEvent() is where that gets reconciled into a single undo step per role, comparing m_original_transform/m_original_pos (captured at press time) against the now-already-applied live values – this is a direct port of that same pattern for this class's own, smaller role set. Pushing a command whose redo() sets a property to what it's already live at is intentional, not wasted: redo() runs once immediately, as a harmless no-op, so the stack has a correct entry for Ctrl+Z without the live drag needing any awareness of undo at all. For Pivot specifically, chaining "pos" before "rawPivot" – not the compensating "pivot" – means undoing simply restores both to their exact recorded values, without a second, redundant compensation needing to run and (correctly, but confusingly) arrive at the same place a longer way around.


|
staticprivate |

|
overrideprotected |
|
overrideprotected |
|
overrideprotected |
|
private |
DiagramImageItem::mirror Context-menu action: flips the pixmap itself, not a transform – unlike QetShapeItem::mirror(), which has rotation/skew to contend with, there's no equivalent linear-transform decomposition needed here: the bitmap is flipped once, directly, and stays flipped regardless of whatever rotation is applied on top afterward.


|
overrideprotected |
DiagramImageItem::mousePressEvent Clicking an already-selected image cycles its handle mode, exactly matching QetShapeItem's own established convention for the same gesture – deliberately kept consistent rather than inventing a different interaction just because this is a different class.

|
overridevirtual |
Reimplemented from QetGraphicsItem.
|
private |
DiagramImageItem::nextHandleMode.

|
overrideprotected |
DiagramImageItem::paint Draw the pixmap.
| painter | the Qpainter to use for draw the pixmap |
| option | the style option |
| widget | the QWidget where we draw the pixmap |


|
inline |
DXF export: replay this item's paint() on an arbitrary QPainter (e.g. one targeting DxfPaintDevice). paint() itself stays protected, as it should for the normal QGraphicsScene/QGraphicsView paint contract - this is a deliberate, narrow escape hatch for exporters, not a general relaxation of that contract. Matches CrossRefItem::paintForExport() exactly, for the identical reason.

|
inline |
|
inline |
|
signal |

|
private |


|
private |
DiagramImageItem::refreshInteractionHints Keeps the tooltip text current, and – if already being hovered – immediately re-shows both the tooltip and the status bar hint rather than leaving them stuck on whatever was true before. Ported from QetShapeItem's identical method, for the identical reason: Qt only re-evaluates a tooltip, and this class only re-shows the status bar, when the cursor moves – selecting an image (often clicked while the mouse was already sitting on it) or cycling handle modes (definitely clicked while sitting on it) both change what should be shown without the cursor moving at all.


|
private |
DiagramImageItem::replaceImage Context-menu action: swaps the underlying pixmap for one loaded from a new file, keeping position, rotation and scale untouched – only pixmap_ changes, everything else about how this item sits on the diagram is left exactly as it was. Reuses the same file dialog filter and error handling as DiagramEventAddImage::openDialog(), so picking a replacement looks and behaves like picking a new image did when this item was first inserted.


|
private |
DiagramImageItem::repositionHandles Moves the existing handle items to match current geometry, without touching their identity – safe to call on every frame of a live drag, matching QetShapeItem's own repositionHandles()/rebuildHandles() split for the identical reason.


|
private |
DiagramImageItem::resetPivotToBoundingRectCenter Used after a resize drag ends (see handlerMouseReleaseEvent()) – NOT after crop() or replaceImage(), which each compute their own, more specific position handling instead (see setPixmap()'s comment for why a single generic rule doesn't fit both of those).


|
private |
DiagramImageItem::restoreAspectRatio Context-menu action, the direct answer to "restoration of aspect ratio" from the original wishlist: makes scaleY match scaleX, keeping the current width fixed. The natural aspect ratio is already fully accounted for by the pixmap's own width/height (a uniform scale, by definition, can never distort it) – the distortion is entirely scaleX and scaleY disagreeing with each other, so undoing it is exactly "make them agree", not a computation involving pixmap_'s own dimensions at all. An earlier version of this multiplied by the natural height/width ratio a second time, which double-counted it and left the image still visibly distorted, just less obviously so.


|
inline |
|
private |
DiagramImageItem::saveImageAs Saves the currently displayed pixmap (crop and colour-keyed transparency already applied – what the item actually looks like on the diagram, not the pristine original) to an arbitrary file on disk.


|
private |
DiagramImageItem::saveImagePixmapAs Shared by saveImageAs() and saveOriginalImageAs(): prompts for a destination, resolves whichever format was actually intended, warns before silently dropping transparency, and writes the file. A read-only export, not an edit: doesn't touch diagram()'s undo stack, and works even on a read-only diagram, unlike every other action in this item's context menu.
| pixmap | the pixmap to save – pixmap_ or m_base_pixmap |
| dialogTitle | distinguishes the two callers in the save dialog's own title bar |
| hasTransparency | whether pixmap has colour-keyed transparency worth warning about losing (never true for the pristine original, which predates any such keying) |


|
private |
DiagramImageItem::saveOriginalImageAs Saves m_base_pixmap – the true, pristine original, before any crop or colour-keyed transparency – rather than the item's current, possibly-cropped-and-keyed display pixmap. The only way to recover the un-cropped, un-keyed source once either of those has actually been applied, short of undoing every edit back to the point it was first inserted or replaced.


|
private |


|
inline |
|
inline |
|
private |
DiagramImageItem::scaleOnlyOffset / scaleAndShearOffset Verbatim ports of QetShapeItem's own identically-named helpers (see their definitions there for the derivation) – the offset of a local point from the pivot, with scale (and, for the second, shear too) applied but rotation deliberately left out. Used by dragRotateHandle()/dragSkewHandle() to solve for rotation/skew directly rather than through mapFromScene(), which would divide out the very value being solved for.

|
overrideprotected |
DiagramImageItem::sceneEventFilter Dispatches handle interaction events – structurally identical to QetShapeItem::sceneEventFilter(), reused as a pattern rather than shared as code, since the two classes' handle roles are different enough (no path/polygon/arc concepts here at all) that sharing the dispatcher itself would need an awkward, indirect abstraction for very little actual code saved.

| void DiagramImageItem::setPivot | ( | const QPointF & | pivot | ) |
DiagramImageItem::setPivot Unlike scale/rotation, moving the pivot alone WOULD visibly shift the image on screen, since the pivot is baked directly into the transform matrix – compensatedPositionForNewPivot() (already proven correct for QetShapeItem's identical need) solves for whatever pos() keeps the image exactly where it already was, so only the handle moves, not the picture underneath it.


| void DiagramImageItem::setPivotRaw | ( | const QPointF & | pivot | ) |
DiagramImageItem::setPivotRaw Sets m_transform.pivot directly, with NO position compensation at all – deliberately, unlike setPivot() above. Exists solely for crop()'s own undo chain (see the Q_PROPERTY declaration's comment for why): crop() already computes the fully correct pos() itself, accounting for the crop, and pushes that as its own independent undo step, so compensating pos() again here would silently corrupt it back to a wrong value the moment this step replays. Never call this expecting the image to stay visually in place on its own – it won't; the caller is responsible for that.

| void DiagramImageItem::setPixmap | ( | const QPixmap & | pixmap | ) |
DiagramImageItem::setPixmap Set the new pixmap to be draw.
| pixmap | the new pixmap |


| void DiagramImageItem::setRotationAngle | ( | qreal | angle | ) |

| void DiagramImageItem::setScaleFactorX | ( | qreal | factor | ) |
DiagramImageItem::setScaleFactorX / setScaleFactorY / setRotationAngle Matching QetShapeItem's own setters for the identical fields – same pattern, same reasoning: change the one field, rebuild the matrix, notify. No pivot or position compensation needed here, unlike setPivot() below, since neither scale nor rotation moves the pivot itself.

| void DiagramImageItem::setScaleFactorY | ( | qreal | factor | ) |

| void DiagramImageItem::setSkewX | ( | qreal | skew | ) |

| void DiagramImageItem::setSkewY | ( | qreal | skew | ) |

|
private |
DiagramImageItem::setTransparentColor Context-menu action: opens ImageTransparentColorDialog against m_base_pixmap (the pristine source), pre-populated with whatever colours and tolerance were remembered from a previous session – both problems fixed together, since they had the same root cause: passing pixmap_ (the already colour-keyed result) as if it were the source, with nowhere to remember which colours produced it. Applies the result the same way replaceImage() and mirror() do, through the "pixmap" property, so undo/redo stays consistent across all three; m_base_pixmap itself is deliberately left untouched here, since this action only ever changes which colours are keyed out of it, not the source those colours are keyed out of.
DiagramImageItem::setTransparentColor Context-menu action: opens ImageTransparentColorDialog against the CROPPED base (m_base_pixmap.copy(m_crop_rect)), not the full, uncropped original – picking a colour from a region that's already been permanently cropped away would be picking a colour that isn't even part of the image anymore. Pre-populated with whatever colours and tolerance were remembered from a previous session. Applies the result the same way replaceImage() and mirror() do, through the "pixmap" property, so undo/redo stays consistent across all three; m_base_pixmap and m_crop_rect are deliberately left untouched here, since this action only ever changes which colours are keyed out, never the source region they're keyed out of.


|
private |
DiagramImageItem::showStatusHint.


|
inline |
|
inline |
|
private |
DiagramImageItem::toggleHandleMode.


|
virtual |
| document | Le document XML a utiliser |

|
signal |

|
inlineoverride |
Enable the use of qgraphicsitem_cast to safely cast a QGraphicsItem into a DiagramImageItem
|
private |
DiagramImageItem::updateModeHint Keeps the tooltip in sync with what the next click would do – called on selection change (so it appears/disappears with the handles themselves) and after every mode switch. Ported from QetShapeItem's identical method: deliberately short, since this is a tooltip, not documentation – the fuller gesture/modifier reference lives in the status bar instead (see currentModeStatusHint(), hoverEnterEvent()).


|
staticprivate |
DiagramImageItem::writeRasterAsSvg Wraps pixmap as a base64-embedded PNG inside a minimal, valid SVG document – the closest this can honestly offer to "save as SVG" given this item only ever holds raster data (see the note in saveImagePixmapAs()). Opens in any SVG viewer at the pixmap's own pixel size, but is not, and cannot be, a vector re-export.
| pixmap | the raster image to embed |
| path | destination file path |

|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
readwrite |
|
readwrite |
|
readwrite |
|
readwrite |
|
readwrite |
|
readwrite |
|
readwrite |
|
readwrite |