You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ktechlab/src/resizeoverlay.cpp

747 lines
19 KiB

/***************************************************************************
* Copyright (C) 2005 by David Saxton *
* david@bluehaze.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
***************************************************************************/
#include "itemdocument.h"
#include "mechanicsitem.h"
#include "resizeoverlay.h"
#include <kdebug.h>
#include <tqpainter.h>
//BEGIN class ResizeOverlay
ResizeOverlay::ResizeOverlay( Item *parent )
: TQObject(parent)
{
b_showResizeHandles = false;
b_visible = true;
p_item = parent;
}
ResizeOverlay::~ResizeOverlay()
{
const ResizeHandleMap::iterator end = m_resizeHandleMap.end();
for ( ResizeHandleMap::iterator it = m_resizeHandleMap.begin(); it != end; ++it )
{
if (it.data())
it.data()->setCanvas(0l);
delete (ResizeHandle*)it.data();
}
m_resizeHandleMap.clear();
}
void ResizeOverlay::showResizeHandles( bool show )
{
b_showResizeHandles = show;
const ResizeHandleMap::iterator end = m_resizeHandleMap.end();
for ( ResizeHandleMap::iterator it = m_resizeHandleMap.begin(); it != end; ++it )
{
it.data()->setVisible(b_showResizeHandles && b_visible);
}
}
void ResizeOverlay::setVisible( bool visible )
{
b_visible = visible;
const ResizeHandleMap::iterator end = m_resizeHandleMap.end();
for ( ResizeHandleMap::iterator it = m_resizeHandleMap.begin(); it != end; ++it )
{
it.data()->setVisible(b_showResizeHandles && b_visible);
}
}
ResizeHandle *ResizeOverlay::createResizeHandle( int id, ResizeHandle::DrawType drawType, int xsnap, int ysnap )
{
ResizeHandleMap::iterator it = m_resizeHandleMap.find(id);
if ( it != m_resizeHandleMap.end() )
return it.data();
ResizeHandle *newResizeHandle = new ResizeHandle( this, id, drawType, xsnap, ysnap );
m_resizeHandleMap[id] = newResizeHandle;
connect( newResizeHandle, TQ_SIGNAL(rhMovedBy(int, double, double )), this, TQ_SLOT(slotResizeHandleMoved(int, double, double )) );
return newResizeHandle;
}
void ResizeOverlay::removeResizeHandle( int id )
{
ResizeHandleMap::iterator it = m_resizeHandleMap.find(id);
if ( it == m_resizeHandleMap.end() )
return;
ResizeHandle *rh = it.data();
disconnect( rh, TQ_SIGNAL(rhMovedBy(int, double, double )), this, TQ_SLOT(slotResizeHandleMoved(int, double, double )) );
delete rh;
m_resizeHandleMap.erase(it);
}
ResizeHandle *ResizeOverlay::resizeHandle( int id )
{
ResizeHandleMap::iterator it = m_resizeHandleMap.find(id);
if ( it != m_resizeHandleMap.end() )
return it.data();
return 0l;
}
void ResizeOverlay::slotMoveAllResizeHandles( double dx, double dy )
{
const ResizeHandleMap::iterator end = m_resizeHandleMap.end();
for ( ResizeHandleMap::iterator it = m_resizeHandleMap.begin(); it != end; ++it )
{
it.data()->moveBy( dx, dy );
}
}
void ResizeOverlay::syncX( ResizeHandle *rh1, ResizeHandle *rh2, ResizeHandle *rh3 )
{
syncX( rh1, rh2 );
syncX( rh1, rh3 );
syncX( rh2, rh3 );
}
void ResizeOverlay::syncY( ResizeHandle *rh1, ResizeHandle *rh2, ResizeHandle *rh3 )
{
syncY( rh1, rh2 );
syncY( rh1, rh3 );
syncY( rh2, rh3 );
}
void ResizeOverlay::syncX( ResizeHandle *rh1, ResizeHandle *rh2 )
{
if ( !rh1 || !rh2 )
return;
connect( rh1, TQ_SIGNAL(rhMovedByX(double )), rh2, TQ_SLOT(slotMoveByX(double )) );
connect( rh2, TQ_SIGNAL(rhMovedByX(double )), rh1, TQ_SLOT(slotMoveByX(double )) );
}
void ResizeOverlay::syncY( ResizeHandle *rh1, ResizeHandle *rh2 )
{
if ( !rh1 || !rh2 )
return;
connect( rh1, TQ_SIGNAL(rhMovedByY(double )), rh2, TQ_SLOT(slotMoveByY(double )) );
connect( rh2, TQ_SIGNAL(rhMovedByY(double )), rh1, TQ_SLOT(slotMoveByY(double )) );
}
//END class ResizeOverlay
//BEGIN class MechanicsItemOverlay
MechanicsItemOverlay::MechanicsItemOverlay( MechanicsItem *parent )
: ResizeOverlay(parent)
{
p_mechanicsItem = parent;
connect( parent, TQ_SIGNAL(moved()), this, TQ_SLOT(slotUpdateResizeHandles()) );
connect( parent, TQ_SIGNAL(resized()), this, TQ_SLOT(slotUpdateResizeHandles()) );
m_tl = createResizeHandle( ResizeHandle::rhp_topLeft, ResizeHandle::dt_resize_backwardsDiagonal );
m_tm = createResizeHandle( ResizeHandle::rhp_topMiddle, ResizeHandle::dt_resize_vertical );
m_tr = createResizeHandle( ResizeHandle::rhp_topRight, ResizeHandle::dt_resize_forwardsDiagonal );
m_mr = createResizeHandle( ResizeHandle::rhp_middleRight, ResizeHandle::dt_resize_horizontal );
m_br = createResizeHandle( ResizeHandle::rhp_bottomRight, ResizeHandle::dt_resize_backwardsDiagonal );
m_bm = createResizeHandle( ResizeHandle::rhp_bottomMiddle, ResizeHandle::dt_resize_vertical );
m_bl = createResizeHandle( ResizeHandle::rhp_bottomLeft, ResizeHandle::dt_resize_forwardsDiagonal );
m_ml = createResizeHandle( ResizeHandle::rhp_middleLeft, ResizeHandle::dt_resize_horizontal );
m_mm = createResizeHandle( ResizeHandle::rhp_center, ResizeHandle::dt_point_crosshair );
slotUpdateResizeHandles();
}
MechanicsItemOverlay::~MechanicsItemOverlay()
{
}
void MechanicsItemOverlay::slotUpdateResizeHandles()
{
const PositionInfo absPos = p_mechanicsItem->absolutePosition();
const TQRect sizeRect = p_mechanicsItem->sizeRect();
TQPointArray pa(9);
pa[0] = sizeRect.topLeft();
pa[2] = sizeRect.topRight();
pa[1] = (pa[0]+pa[2])/2;
pa[4] = sizeRect.bottomRight();
pa[3] = (pa[2]+pa[4])/2;
pa[6] = sizeRect.bottomLeft();
pa[5] = (pa[4]+pa[6])/2;
pa[7] = (pa[6]+pa[0])/2;
pa[8] = TQPoint(0,0);
TQWMatrix m;
m.rotate(absPos.angle()*57.29577951308232);
pa = m.map(pa);
m_tl->move( absPos.x()+pa[0].x(), absPos.y()+pa[0].y() );
m_tm->move( absPos.x()+pa[1].x(), absPos.y()+pa[1].y() );
m_tr->move( absPos.x()+pa[2].x(), absPos.y()+pa[2].y() );
m_mr->move( absPos.x()+pa[3].x(), absPos.y()+pa[3].y() );
m_br->move( absPos.x()+pa[4].x(), absPos.y()+pa[4].y() );
m_bm->move( absPos.x()+pa[5].x(), absPos.y()+pa[5].y() );
m_bl->move( absPos.x()+pa[6].x(), absPos.y()+pa[6].y() );
m_ml->move( absPos.x()+pa[7].x(), absPos.y()+pa[7].y() );
m_mm->move( absPos.x()+pa[8].x(), absPos.y()+pa[8].y() );
}
void MechanicsItemOverlay::slotResizeHandleMoved( int id, double dx, double dy )
{
Q_UNUSED(id);
Q_UNUSED(dx);
Q_UNUSED(dy);
switch (id)
{
case ResizeHandle::rhp_topLeft:
break;
case ResizeHandle::rhp_topMiddle:
break;
case ResizeHandle::rhp_topRight:
break;
case ResizeHandle::rhp_middleRight:
break;
case ResizeHandle::rhp_bottomRight:
break;
case ResizeHandle::rhp_bottomMiddle:
break;
case ResizeHandle::rhp_bottomLeft:
break;
case ResizeHandle::rhp_middleLeft:
break;
case ResizeHandle::rhp_center:
break;
default:
kdError() << k_funcinfo << "Unknown resize handle id " << id << endl;
break;
}
}
//END class MechanicsItemOverlay
//BEGIN class RectangularOverlay
RectangularOverlay::RectangularOverlay( Item *parent, int xsnap, int ysnap )
: ResizeOverlay(parent)
{
connect( parent, TQ_SIGNAL(resized()), this, TQ_SLOT(slotUpdateResizeHandles()) );
connect( parent, TQ_SIGNAL(movedBy(double, double )), this, TQ_SLOT(slotMoveAllResizeHandles(double, double )) );
m_tl = createResizeHandle( ResizeHandle::rhp_topLeft, ResizeHandle::dt_resize_backwardsDiagonal, xsnap, ysnap );
m_tm = createResizeHandle( ResizeHandle::rhp_topMiddle, ResizeHandle::dt_resize_vertical, xsnap, ysnap );
m_tr = createResizeHandle( ResizeHandle::rhp_topRight, ResizeHandle::dt_resize_forwardsDiagonal, xsnap, ysnap );
m_mr = createResizeHandle( ResizeHandle::rhp_middleRight, ResizeHandle::dt_resize_horizontal, xsnap, ysnap );
m_br = createResizeHandle( ResizeHandle::rhp_bottomRight, ResizeHandle::dt_resize_backwardsDiagonal, xsnap, ysnap );
m_bm = createResizeHandle( ResizeHandle::rhp_bottomMiddle, ResizeHandle::dt_resize_vertical, xsnap, ysnap );
m_bl = createResizeHandle( ResizeHandle::rhp_bottomLeft, ResizeHandle::dt_resize_forwardsDiagonal, xsnap, ysnap );
m_ml = createResizeHandle( ResizeHandle::rhp_middleLeft, ResizeHandle::dt_resize_horizontal, xsnap, ysnap );
syncX( m_tl, m_ml, m_bl );
syncX( m_tr, m_mr, m_br );
syncY( m_tl, m_tm, m_tr );
syncY( m_bl, m_bm, m_br );
slotUpdateResizeHandles();
}
void RectangularOverlay::removeTopMiddle()
{
if (!m_tm)
return;
removeResizeHandle( m_tm->id() );
m_tm = 0l;
}
void RectangularOverlay::removeBotMiddle()
{
if (!m_bm)
return;
removeResizeHandle( m_bm->id() );
m_bm = 0l;
}
void RectangularOverlay::slotUpdateResizeHandles()
{
const TQRect sizeRect = p_item->sizeRect();
int x1 = sizeRect.left() + int(p_item->x());
int x2 = x1 + sizeRect.width();
int y1 = sizeRect.top() + int(p_item->y());
int y2 = y1 + sizeRect.height();
m_tl->move( x1, y1 );
if (m_tm)
m_tm->move( (x1+x2)/2, y1 );
m_tr->move( x2, y1 );
m_mr->move( x2, (y1+y2)/2 );
m_br->move( x2, y2 );
if (m_bm)
m_bm->move( (x1+x2)/2, y2 );
m_bl->move( x1, y2 );
m_ml->move( x1, (y1+y2)/2 );
}
bool RectangularOverlay::isValidXPos( ResizeHandle *rh )
{
Q_UNUSED(rh);
bool ok;
getSizeRect( 0l, &ok, 0l );
return ok;
}
bool RectangularOverlay::isValidYPos( ResizeHandle *rh )
{
Q_UNUSED(rh);
bool ok;
getSizeRect( 0l, 0l, &ok );
return ok;
}
void RectangularOverlay::slotResizeHandleMoved( int id, double dx, double dy )
{
Q_UNUSED(id);
Q_UNUSED(dx);
Q_UNUSED(dy);
bool ok;
TQRect sizeRect = getSizeRect(&ok);
if (!ok)
return;
p_item->setSize(sizeRect);
slotUpdateResizeHandles();
}
TQRect RectangularOverlay::getSizeRect( bool *ok, bool *widthOk, bool *heightOk ) const
{
bool t1,t2,t3;
if (!ok)
ok = &t1;
if (!widthOk)
widthOk = &t2;
if (!heightOk)
heightOk = &t3;
int width = int(m_br->x() - m_tl->x());
int height = int(m_br->y() - m_tl->y());
TQRect sizeRect( int(m_tl->x() - p_item->x()),
int(m_tl->y() - p_item->y()),
width, height );
*widthOk = sizeRect.width() >= p_item->minimumSize().width();
*heightOk = sizeRect.height() >= p_item->minimumSize().height();
*ok = *widthOk && *heightOk;
return sizeRect;
}
//END class RectangularOverlay
//BEGIN class LineOverlay
LineOverlay::LineOverlay( Item * parent )
: ResizeOverlay(parent)
{
connect( parent, TQ_SIGNAL(resized()), this, TQ_SLOT(slotUpdateResizeHandles()) );
connect( parent, TQ_SIGNAL(movedBy(double, double )), this, TQ_SLOT(slotMoveAllResizeHandles(double, double )) );
m_pStart = createResizeHandle( ResizeHandle::rhp_start, ResizeHandle::dt_point_rect );
m_pEnd = createResizeHandle( ResizeHandle::rhp_end, ResizeHandle::dt_point_rect );
slotUpdateResizeHandles();
}
TQPoint LineOverlay::startPoint() const
{
return TQPoint( int(m_pStart->x()), int(m_pStart->y()) );
}
TQPoint LineOverlay::endPoint() const
{
return TQPoint( int(m_pEnd->x()), int(m_pEnd->y()) );
}
void LineOverlay::slotUpdateResizeHandles()
{
int _x = int(p_item->x() + p_item->offsetX());
int _y = int(p_item->y() + p_item->offsetY());
m_pStart->move( _x, _y );
m_pEnd->move( _x+p_item->width(), _y+p_item->height() );
}
void LineOverlay::slotResizeHandleMoved( int id, double dx, double dy )
{
Q_UNUSED(id);
Q_UNUSED(dx);
Q_UNUSED(dy);
p_item->setSize( int(m_pStart->x()-p_item->x()), int(m_pStart->y()-p_item->y()),
int(m_pEnd->x()-m_pStart->x()), int(m_pEnd->y()-m_pStart->y()) );
}
//END class LineOverlay
//BEGIN class ResizeHandle
ResizeHandle::ResizeHandle( ResizeOverlay *resizeOverlay, int id, DrawType drawType, int xsnap, int ysnap )
: TQObject(), TQCanvasRectangle( 0, 0, 13, 13, resizeOverlay->parentItem()->canvas() )
{
p_resizeOverlay = resizeOverlay;
m_drawType = drawType;
m_id = id;
b_hover = false;
m_xsnap = xsnap;
m_ysnap = ysnap;
setZ( ItemDocument::Z::ResizeHandle );
}
ResizeHandle::~ResizeHandle()
{
hide();
}
int ResizeHandle::rtti() const
{
return ItemDocument::RTTI::ResizeHandle;
}
void ResizeHandle::setHover( bool hover )
{
if ( b_hover == hover )
return;
b_hover = hover;
canvas()->setChanged( TQRect( int(x())-8, int(y())-8, 15, 15 ) );
}
TQPointArray ResizeHandle::areaPoints() const
{
// TQPointArray pa = TQCanvasRectangle::areaPoints();
// pa.translate( -7, -7 );
// return pa;
return TQPointArray( TQRect( int(x())-8, int(y())-8, 15, 15 ) );
}
void ResizeHandle::moveRH( double _x, double _y )
{
double dx = int((_x-4)/m_xsnap)*m_xsnap+4 - x();
double dy = int((_y-4)/m_ysnap)*m_ysnap+4 - y();
if ( (dx == 0) && (dy == 0) )
return;
//BEGIN Move and check
moveBy( dx, dy );
if ( dx != 0 )
emit rhMovedByX(dx);
if ( dy != 0 )
emit rhMovedByY(dy);
bool xOk = p_resizeOverlay->isValidXPos(this);
bool yOk = p_resizeOverlay->isValidYPos(this);
if (!xOk)
{
moveBy( -dx, 0 );
emit rhMovedByX(-dx);
dx = 0;
}
if (!yOk)
{
moveBy( 0, -dy );
emit rhMovedByY(-dy);
dy = 0;
}
if ( !xOk && !yOk )
return;
//END Move and check
emit rhMovedBy( id(), dx, dy );
}
void ResizeHandle::setDrawType( DrawType drawType )
{
m_drawType = drawType;
canvas()->setChanged(boundingRect());
}
void ResizeHandle::drawShape( TQPainter &p )
{
p.drawPixmap( rect().topLeft()-TQPoint( 7, 7 ), handlePixmap( m_drawType, b_hover ) );
}
const TQPixmap& ResizeHandle::handlePixmap( DrawType drawType, bool hover )
{
const char * resize_forwardsDiagonal_hover_xpm[] = {
"13 13 3 1",
" c None",
". c #000000",
"+ c #8EA5D0",
" ",
" ....... ",
" ..+++. ",
" .++++. ",
" .+++++. ",
" . .+++++.. ",
" ...+++++... ",
" ..+++++. . ",
" .+++++. ",
" .++++. ",
" .+++.. ",
" ....... ",
" "};
static TQPixmap pixmap_forwardsDiagonal_hover(resize_forwardsDiagonal_hover_xpm);
const char * resize_forwardsDiagonal_nohover_xpm[] = {
"13 13 2 1",
" c None",
". c #000000",
" ",
" ....... ",
" ...... ",
" ...... ",
" ....... ",
" . ........ ",
" ........... ",
" ........ . ",
" ....... ",
" ...... ",
" ...... ",
" ....... ",
" "};
static TQPixmap pixmap_forwardsDiagonal_nohover(resize_forwardsDiagonal_nohover_xpm);
const char * resize_backwardsDiagonal_hover_xpm[] = {
"13 13 3 1",
" c None",
". c #000000",
"+ c #8EA5D0",
" ",
" ....... ",
" .+++.. ",
" .++++. ",
" .+++++. ",
" ..+++++. . ",
" ...+++++... ",
" . .+++++.. ",
" .+++++. ",
" .++++. ",
" ..+++. ",
" ....... ",
" "};
static TQPixmap pixmap_backwardsDiagonal_hover(resize_backwardsDiagonal_hover_xpm);
const char * resize_backwardsDiagonal_nohover_xpm[] = {
"13 13 2 1",
" c None",
". c #000000",
" ",
" ....... ",
" ...... ",
" ...... ",
" ....... ",
" ........ . ",
" ........... ",
" . ........ ",
" ....... ",
" ...... ",
" ...... ",
" ....... ",
" "};
static TQPixmap pixmap_backwardsDiagonal_nohover(resize_backwardsDiagonal_nohover_xpm);
const char * resize_vertical_hover_xpm[] = {
"13 13 3 1",
" c None",
". c #000000",
"+ c #8EA5D0",
" . ",
" ... ",
" ..+.. ",
" ..+++.. ",
" ..+++++.. ",
" .+++. ",
" .+++. ",
" .+++. ",
" ..+++++.. ",
" ..+++.. ",
" ..+.. ",
" ... ",
" . "};
static TQPixmap pixmap_vertical_hover(resize_vertical_hover_xpm);
const char * resize_vertical_nohover_xpm[] = {
"13 13 2 1",
" c None",
". c #000000",
" . ",
" ... ",
" ..... ",
" ....... ",
" ......... ",
" ..... ",
" ..... ",
" ..... ",
" ......... ",
" ....... ",
" ..... ",
" ... ",
" . "};
static TQPixmap pixmap_vertical_nohover(resize_vertical_nohover_xpm);
const char * resize_horizontal_hover_xpm[] = {
"13 13 3 1",
" c None",
". c #000000",
"+ c #8EA5D0",
" ",
" ",
" . . ",
" .. .. ",
" ..+...+.. ",
" ..+++++++.. ",
"..+++++++++..",
" ..+++++++.. ",
" ..+...+.. ",
" .. .. ",
" . . ",
" ",
" "};
static TQPixmap pixmap_horizontal_hover(resize_horizontal_hover_xpm);
const char * resize_horizontal_nohover_xpm[] = {
"13 13 2 1",
" c None",
". c #000000",
" ",
" ",
" . . ",
" .. .. ",
" ......... ",
" ........... ",
".............",
" ........... ",
" ......... ",
" .. .. ",
" . . ",
" ",
" "};
static TQPixmap pixmap_horizontal_nohover(resize_horizontal_nohover_xpm);
const char * point_rect_hover_xpm[] = {
"13 13 3 1",
" c None",
". c #000000",
"+ c #8EA5D0",
" ",
" ",
" ",
" ",
" ",
" ..... ",
" .+++. ",
" .+++. ",
" .+++. ",
" ..... ",
" ",
" ",
" "};
static TQPixmap pixmap_point_rect_hover(point_rect_hover_xpm);
const char * point_rect_nohover_xpm[] = {
"13 13 3 1",
" c None",
". c #000000",
"+ c #FFFFFF",
" ",
" ",
" ",
" ",
" ",
" ..... ",
" .+++. ",
" .+++. ",
" .+++. ",
" ..... ",
" ",
" ",
" "};
static TQPixmap pixmap_point_rect_nohover(point_rect_nohover_xpm);
if (hover)
{
switch(drawType)
{
case ResizeHandle::dt_resize_forwardsDiagonal:
return pixmap_forwardsDiagonal_hover;
case ResizeHandle::dt_resize_backwardsDiagonal:
return pixmap_backwardsDiagonal_hover;
case ResizeHandle::dt_resize_vertical:
return pixmap_vertical_hover;
case ResizeHandle::dt_resize_horizontal:
return pixmap_horizontal_hover;
case ResizeHandle::dt_point_rect:
return pixmap_point_rect_hover;
case ResizeHandle::dt_point_crosshair:
case ResizeHandle::dt_rotate_topLeft:
case ResizeHandle::dt_rotate_topRight:
case ResizeHandle::dt_rotate_bottomRight:
case ResizeHandle::dt_rotate_bottomLeft:
kdWarning() << k_funcinfo << "ResizeHandle of type " << drawType << " does not have an image." << endl;
}
}
else
{
switch(drawType)
{
case ResizeHandle::dt_resize_forwardsDiagonal:
return pixmap_forwardsDiagonal_nohover;
case ResizeHandle::dt_resize_backwardsDiagonal:
return pixmap_backwardsDiagonal_nohover;
case ResizeHandle::dt_resize_vertical:
return pixmap_vertical_nohover;
case ResizeHandle::dt_resize_horizontal:
return pixmap_horizontal_nohover;
case ResizeHandle::dt_point_rect:
return pixmap_point_rect_nohover;
case ResizeHandle::dt_point_crosshair:
case ResizeHandle::dt_rotate_topLeft:
case ResizeHandle::dt_rotate_topRight:
case ResizeHandle::dt_rotate_bottomRight:
case ResizeHandle::dt_rotate_bottomLeft:
kdWarning() << k_funcinfo << "ResizeHandle of type " << drawType << " does not have an image." << endl;
}
}
static TQPixmap blank;
return blank;
}
//END class ResizeHandle
#include "resizeoverlay.moc"