/* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2004 Cedric Pasteur This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include // for abs() #include "utils.h" #include "container.h" #include "widgetlibrary.h" #include "objecttree.h" #include "form.h" #include "formmanager.h" #include "commands.h" #include "events.h" #include "kexiflowlayout.h" using namespace KFormDesigner; EventEater::EventEater(QWidget *widget, QObject *container) : QObject(container) { m_widget = widget; m_container = container; installRecursiveEventFilter(m_widget, this); } bool EventEater::eventFilter(QObject *, QEvent *ev) { if(!m_container) return false; // When the user click the empty part of tab bar, only MouseReleaseEvent is sent, // we need to simulate the Press event if(ev->type() == QEvent::MouseButtonRelease && m_widget->inherits("QTabWidget")) { QMouseEvent *mev = static_cast(ev); if(mev->button() == LeftButton) { QMouseEvent *myev = new QMouseEvent(QEvent::MouseButtonPress, mev->pos(), mev->button(), mev->state()); m_container->eventFilter(m_widget, myev); delete myev; //return true; } } // else if(ev->type() == QEvent::ChildInserted) { // widget's children have changed, we need to reinstall filter // installRecursiveEventFilter(m_widget, this); // } return m_container->eventFilter(m_widget, ev); } EventEater::~EventEater() { if(m_widget) removeRecursiveEventFilter(m_widget, this); } // Container itself Container::Container(Container *toplevel, QWidget *container, QObject *parent, const char *name) : QObject(parent, name) , m_insertBegin(-1,-1) , m_mousePressEventReceived(false) , m_mouseReleaseEvent(QEvent::None, QPoint(), 0, 0) { m_container = container; m_toplevel = toplevel; m_moving = 0; m_tree = 0; m_form = toplevel ? toplevel->form() : 0; m_layout = 0; m_layType = NoLayout; m_state = DoingNothing; QCString classname = container->className(); if((classname == "HBox") || (classname == "Grid") || (classname == "VBox") || (classname == "HFlow") || (classname == "VFlow")) m_margin = 4; // those containers don't have frames, so little margin else m_margin = m_form ? m_form->defaultMargin() : 0; m_spacing = m_form ? m_form->defaultSpacing() : 0; if(toplevel) { ObjectTreeItem *it = new ObjectTreeItem(m_form->library()->displayName(classname), widget()->name(), widget(), this, this); setObjectTree(it); if(parent->isWidgetType()) { QString n = parent->name(); ObjectTreeItem *parent = m_form->objectTree()->lookup(n); m_form->objectTree()->addItem(parent, it); } else m_form->objectTree()->addItem(toplevel->objectTree(), it); connect(toplevel, SIGNAL(destroyed()), this, SLOT(widgetDeleted())); } connect(container, SIGNAL(destroyed()), this, SLOT(widgetDeleted())); } Container::~Container() { kdDebug() << " Container being deleted this == " << name() << endl; } void Container::setForm(Form *form) { m_form = form; m_margin = m_form ? m_form->defaultMargin() : 0; m_spacing = m_form ? m_form->defaultSpacing() : 0; } bool Container::eventFilter(QObject *s, QEvent *e) { // kdDebug() << e->type() << endl; switch(e->type()) { case QEvent::MouseButtonPress: { m_insertBegin = QPoint(-1, -1); m_mousePressEventReceived = true; kdDebug() << "QEvent::MouseButtonPress sender object = " << s->name() << "of type " << s->className() << endl; kdDebug() << "QEvent::MouseButtonPress this = " << name() << endl; m_moving = static_cast(s); QMouseEvent *mev = static_cast(e); m_grab = QPoint(mev->x(), mev->y()); // we are drawing a connection if(FormManager::self()->isCreatingConnection()) { drawConnection(mev); return true; } if(((mev->state() == ControlButton) || (mev->state() == ShiftButton)) && (!FormManager::self()->isInserting())) // multiple selection mode { if(m_form->selectedWidgets()->findRef(m_moving) != -1) // widget is already selected { if(m_form->selectedWidgets()->count() > 1) // we remove it from selection unSelectWidget(m_moving); else // the widget is the only selected, so it means we want to copy it { //m_copyRect = m_moving->geometry(); m_state = CopyingWidget; if(m_form->formWidget()) m_form->formWidget()->initBuffer(); } } else // the widget is not yet selected, we add it setSelectedWidget(m_moving, true, (mev->button() == RightButton)); } else if((m_form->selectedWidgets()->count() > 1))//&& (!m_form->manager()->isInserting())) // more than one widget selected { if(m_form->selectedWidgets()->findRef(m_moving) == -1) // widget is not selected, it becomes the only selected widget setSelectedWidget(m_moving, false, (mev->button() == RightButton)); // If the widget is already selected, we do nothing (to ease widget moving, etc.) } else// if(!m_form->manager()->isInserting()) setSelectedWidget(m_moving, false, (mev->button() == RightButton)); // we are inserting a widget or drawing a selection rect in the form if((/*s == m_container &&*/ FormManager::self()->isInserting()) || ((s == m_container) && !m_toplevel)) { int tmpx,tmpy; if(!FormManager::self()->snapWidgetsToGrid() || (mev->state() == (LeftButton|ControlButton|AltButton))) { tmpx = mev->x(); tmpy = mev->y(); } else { int gridX = m_form->gridSize(); int gridY = m_form->gridSize(); tmpx = int( (float)mev->x() / ((float)gridX) + 0.5 ); // snap to grid tmpx *= gridX; tmpy = int( (float)mev->y() / ((float)gridY) + 0.5 ); tmpy *= gridX; } m_insertBegin = (static_cast(s))->mapTo(m_container, QPoint(tmpx, tmpy)); if(m_form->formWidget()) m_form->formWidget()->initBuffer(); if(!FormManager::self()->isInserting()) m_state = DrawingSelectionRect; } else { if(s->inherits("QTabWidget")) // to allow changing page by clicking tab return false; } if (m_objectForMouseReleaseEvent) { const bool res = handleMouseReleaseEvent(m_objectForMouseReleaseEvent, &m_mouseReleaseEvent); m_objectForMouseReleaseEvent = 0; return res; } return true; } case QEvent::MouseButtonRelease: { QMouseEvent *mev = static_cast(e); if (!m_mousePressEventReceived) { m_mouseReleaseEvent = *mev; m_objectForMouseReleaseEvent = s; return true; } m_mousePressEventReceived = false; m_objectForMouseReleaseEvent = 0; return handleMouseReleaseEvent(s, mev); } case QEvent::MouseMove: { QMouseEvent *mev = static_cast(e); if(m_insertBegin!=QPoint(-1,-1) && FormManager::self()->isInserting() && ((mev->state() == LeftButton) || (mev->state() == (LeftButton|ControlButton)) || (mev->state() == (LeftButton|ControlButton|AltButton)) || (mev->state() == (LeftButton|ShiftButton)) ) ) // draw the insert rect { drawInsertRect(mev, s); return true; } // Creating a connection, we highlight sender and receiver, and we draw a link between them else if(FormManager::self()->isCreatingConnection() && !FormManager::self()->createdConnection()->sender().isNull()) { ObjectTreeItem *tree = m_form->objectTree()->lookup(FormManager::self()->createdConnection()->sender()); if(!tree || !tree->widget()) return true; if(m_form->formWidget() && (tree->widget() != s)) m_form->formWidget()->highlightWidgets(tree->widget(), static_cast(s)); } else if(m_insertBegin!=QPoint(-1,-1) && s == m_container && !m_toplevel && (mev->state() != ControlButton) && !FormManager::self()->isCreatingConnection()) // draw the selection rect { if((mev->state() != LeftButton) || /*m_inlineEditing*/ m_state == InlineEditing) return true; int topx = (m_insertBegin.x() < mev->x()) ? m_insertBegin.x() : mev->x(); int topy = (m_insertBegin.y() < mev->y()) ? m_insertBegin.y() : mev->y(); int botx = (m_insertBegin.x() > mev->x()) ? m_insertBegin.x() : mev->x(); int boty = (m_insertBegin.y() > mev->y()) ? m_insertBegin.y() : mev->y(); QRect r = QRect(QPoint(topx, topy), QPoint(botx, boty)); m_insertRect = r; if(m_form->formWidget()) m_form->formWidget()->drawRect(r, 1); m_state = DoingNothing; return true; } else if(mev->state() == (LeftButton|ControlButton)) // draw the insert rect for the copied widget { if(s == m_container)// || (m_form->selectedWidgets()->count() > 1)) return true; drawCopiedWidgetRect(mev); return true; } else if( ( (mev->state() == Qt::LeftButton) || (mev->state() == (LeftButton|ControlButton|AltButton)) ) && !FormManager::self()->isInserting() && (m_state != CopyingWidget)) // we are dragging the widget(s) to move it { if(!m_toplevel && m_moving == m_container) // no effect for form return false; if((!m_moving) || (!m_moving->parentWidget()))// || (m_moving->parentWidget()->inherits("QWidgetStack"))) return true; moveSelectedWidgetsBy(mev->x() - m_grab.x(), mev->y() - m_grab.y()); m_state = MovingWidget; } return true; // eat } case QEvent::Paint: // Draw the dotted background { if(s != m_container) return false; int gridX = m_form->gridSize(); int gridY = m_form->gridSize(); QPainter p(m_container); p.setPen(QPen(white, 2)); p.setRasterOp(XorROP); int cols = m_container->width() / gridX; int rows = m_container->height() / gridY; for(int rowcursor = 1; rowcursor <= rows; ++rowcursor) { for(int colcursor = 1; colcursor <= cols; ++colcursor) { p.drawPoint(-1 + colcursor *gridX, -1 + rowcursor *gridY); } } return false; } case QEvent::Resize: // we are resizing a widget, so we set m_move to true -> the layout will be reloaded when releasing mouse { if(m_form->interactiveMode()) m_state = MovingWidget; break; } //case QEvent::AccelOverride: case QEvent::KeyPress: { QKeyEvent *kev = static_cast(e); if(kev->key() == Key_F2) // pressing F2 == double-clicking { m_state = InlineEditing; QWidget *w; // try to find the widget which was clicked last and should be edited if(m_form->selectedWidgets()->count() == 1) w = m_form->selectedWidgets()->first(); else if(m_form->selectedWidgets()->findRef(m_moving) != -1) w = m_moving; else w = m_form->selectedWidgets()->last(); m_form->library()->startEditing(w->className(), w, this); } else if(kev->key() == Key_Escape) { if(FormManager::self()->isCreatingConnection()) FormManager::self()->stopCreatingConnection(); else if(FormManager::self()->isInserting()) FormManager::self()->stopInsert(); return true; } else if((kev->key() == Key_Control) && (m_state == MovingWidget)) { if(!m_moving) return true; // we simulate a mouse move event to update screen QMouseEvent *mev = new QMouseEvent(QEvent::MouseMove, m_moving->mapFromGlobal(QCursor::pos()), NoButton, LeftButton|ControlButton ); eventFilter(m_moving, mev); delete mev; } else if(kev->key() == FormManager::self()->contextMenuKey()) { FormManager::self()->createContextMenu(static_cast(s), this, false); return true; } else if (kev->key() == Key_Delete) { FormManager::self()->deleteWidget(); return true; } // directional buttons move the widget else if(kev->key() == Key_Left){ // move the widget of gridX to the left moveSelectedWidgetsBy(-form()->gridSize(), 0); return true; } else if(kev->key() == Key_Right){ // move the widget of gridX to the right moveSelectedWidgetsBy(form()->gridSize(), 0); return true; } else if(kev->key() == Key_Up){ // move the widget of gridY to the top moveSelectedWidgetsBy(0, - form()->gridSize()); return true; } else if(kev->key() == Key_Down){ // move the widget of gridX to the bottom moveSelectedWidgetsBy(0, form()->gridSize()); return true; } else if((kev->key() == Key_Tab) || (kev->key() == Key_BackTab)){ ObjectTreeItem *item = form()->objectTree()->lookup(form()->selectedWidgets()->first()->name()); if(!item || !item->parent()) return true; ObjectTreeList *list = item->parent()->children(); if(list->count() == 1) return true; int index = list->findRef(item); if(kev->key() == Key_BackTab){ if(index == 0) // go back to the last item index = list->count() - 1; else index = index - 1; } else { if(index == int(list->count() - 1)) // go back to the first item index = 0; else index = index + 1; } ObjectTreeItem *nextItem = list->at(index); if(nextItem && nextItem->widget()) form()->setSelectedWidget(nextItem->widget(), false); } return true; } case QEvent::KeyRelease: { QKeyEvent *kev = static_cast(e); if((kev->key() == Key_Control) && (m_state == CopyingWidget)) { // cancel copying //m_copyRect = QRect(); if(m_form->formWidget()) m_form->formWidget()->clearForm(); } return true; } case QEvent::MouseButtonDblClick: // editing { kdDebug() << "Container: Mouse dbl click for widget " << s->name() << endl; QWidget *w = static_cast(s); if(!w) return false; //m_inlineEditing = true; m_state = InlineEditing; m_form->library()->startEditing(w->className(), w, this); return true; } case QEvent::ContextMenu: case QEvent::Enter: case QEvent::Leave: case QEvent::FocusIn: case QEvent::FocusOut: // case QEvent::DragEnter: // case QEvent::DragMove: // case QEvent::DragLeave: return true; // eat them default: return false; // let the widget do the rest ... } return false; } bool Container::handleMouseReleaseEvent(QObject *s, QMouseEvent *mev) { if(FormManager::self()->isInserting()) // we insert the widget at cursor pos { if(m_form->formWidget()) m_form->formWidget()->clearForm(); KCommand *com = new InsertWidgetCommand(this/*, mev->pos()*/); m_form->addCommand(com, true); m_insertBegin = QPoint(-1,-1); m_insertRect = QRect(); return true; } else if(s == m_container && !m_toplevel && (mev->button() != RightButton) && m_insertRect.isValid()) // we are drawing a rect to select widgets { drawSelectionRect(mev); return true; } if(mev->button() == RightButton) // Right-click -> context menu { FormManager::self()->createContextMenu(static_cast(s), this); } else if(mev->state() == (Qt::LeftButton|Qt::ControlButton))// && (m_copyRect.isValid())) { // copying a widget by Ctrl+dragging if(m_form->formWidget()) m_form->formWidget()->clearForm(); if(s == m_container) // should have no effect on form return true; // prevent accidental copying of widget (when moving mouse a little while selecting) if( ( (mev->pos().x() - m_grab.x()) < form()->gridSize() && (m_grab.x() - mev->pos().x()) < form()->gridSize() ) && ( (mev->pos().y() - m_grab.y()) < form()->gridSize() && (m_grab.y() - mev->pos().y()) < form()->gridSize() ) ) { kdDebug() << "The widget has not been moved. No copying" << endl; return true; } m_form->setInteractiveMode(false); // We simulate copy and paste FormManager::self()->copyWidget(); if(m_form->selectedWidgets()->count() > 1) FormManager::self()->setInsertPoint( mev->pos() ); else FormManager::self()->setInsertPoint( static_cast(s)->mapTo(m_container, mev->pos() - m_grab) ); FormManager::self()->pasteWidget(); m_form->setInteractiveMode(true); //m_initialPos = QPoint(); } else if(m_state == MovingWidget) // one widget has been moved, so we need to update the layout reloadLayout(); // cancel copying as user released Ctrl before releasing mouse button m_insertBegin = QPoint(-1,-1); m_insertRect = QRect(); m_state = DoingNothing; return true; // eat } void Container::setSelectedWidget(QWidget *w, bool add, bool dontRaise, bool moreWillBeSelected) { if (w) kdDebug() << "slotSelectionChanged " << w->name()<< endl; if(!w) { m_form->setSelectedWidget(m_container); return; } m_form->setSelectedWidget(w, add, dontRaise, moreWillBeSelected); } void Container::unSelectWidget(QWidget *w) { if(!w) return; m_form->unSelectWidget(w); } Container* Container::toplevel() { if(m_toplevel) return m_toplevel; else return this; } void Container::deleteWidget(QWidget *w) { if(!w) return; // kdDebug() << "Deleting a widget: " << w->name() << endl; m_form->objectTree()->removeItem(w->name()); FormManager::self()->deleteWidgetLater( w ); m_form->setSelectedWidget(m_container); } void Container::widgetDeleted() { m_container = 0; deleteLater(); } /// Layout functions void Container::setLayout(LayoutType type) { if(m_layType == type) return; delete m_layout; m_layout = 0; m_layType = type; switch(type) { case HBox: { m_layout = (QLayout*) new QHBoxLayout(m_container, m_margin, m_spacing); createBoxLayout(new HorWidgetList(m_form->toplevelContainer()->widget())); break; } case VBox: { m_layout = (QLayout*) new QVBoxLayout(m_container, m_margin, m_spacing); createBoxLayout(new VerWidgetList(m_form->toplevelContainer()->widget())); break; } case Grid: { createGridLayout(); break; } case HFlow: { KexiFlowLayout *flow = new KexiFlowLayout(m_container,m_margin, m_spacing); flow->setOrientation(Horizontal); m_layout = (QLayout*)flow; createFlowLayout(); break; } case VFlow: { KexiFlowLayout *flow = new KexiFlowLayout(m_container,m_margin, m_spacing); flow->setOrientation(Vertical); m_layout = (QLayout*)flow; createFlowLayout(); break; } default: { m_layType = NoLayout; return; } } m_container->setGeometry(m_container->geometry()); // just update layout m_layout->activate(); } void Container::reloadLayout() { LayoutType type = m_layType; setLayout(NoLayout); setLayout(type); } void Container::createBoxLayout(WidgetList *list) { QBoxLayout *layout = static_cast(m_layout); for(ObjectTreeItem *tree = m_tree->children()->first(); tree; tree = m_tree->children()->next()) list->append( tree->widget()); list->sort(); for(QWidget *obj = list->first(); obj; obj = list->next()) layout->addWidget(obj); delete list; } void Container::createFlowLayout() { KexiFlowLayout *flow = dynamic_cast(m_layout); if(!flow || m_tree->children()->isEmpty()) return; const int offset = 15; WidgetList *list=0, *list2=0; if(flow->orientation() == Horizontal) { list = new VerWidgetList(m_form->toplevelContainer()->widget()); list2 = new HorWidgetList(m_form->toplevelContainer()->widget()); } else { list = new HorWidgetList(m_form->toplevelContainer()->widget()); list2 = new VerWidgetList(m_form->toplevelContainer()->widget()); } // fill the list for(ObjectTreeItem *tree = m_tree->children()->first(); tree; tree = m_tree->children()->next()) list->append( tree->widget()); list->sort(); if(flow->orientation() == Horizontal) { int y = list->first()->y(); for(QWidget *w = list->first(); w; w = list->next()) { if( (w->y() > y +offset)) { // start a new line list2->sort(); for(QWidget *obj = list2->first(); obj; obj = list2->next()) flow->add(obj); list2->clear(); y = w->y(); } list2->append(w); } list2->sort(); // don't forget the last line for(QWidget *obj = list2->first(); obj; obj = list2->next()) flow->add(obj); } else { int x = list->first()->x(); for(QWidget *w = list->first(); w; w = list->next()) { if( (w->x() > x +offset)) { // start a new column list2->sort(); for(QWidget *obj = list2->first(); obj; obj = list2->next()) flow->add(obj); list2->clear(); x = w->x(); } list2->append(w); } list2->sort(); // don't forget the last column for(QWidget *obj = list2->first(); obj; obj = list2->next()) flow->add(obj); } delete list; delete list2; } void Container::createGridLayout(bool testOnly) { //Those lists sort widgets by y and x VerWidgetList *vlist = new VerWidgetList(m_form->toplevelContainer()->widget()); HorWidgetList *hlist = new HorWidgetList(m_form->toplevelContainer()->widget()); // The vector are used to store the x (or y) beginning of each column (or row) QValueVector cols; QValueVector rows; int end=-1000; bool same = false; for(ObjectTreeItem *tree = m_tree->children()->first(); tree; tree = m_tree->children()->next()) vlist->append( tree->widget()); vlist->sort(); for(ObjectTreeItem *tree = m_tree->children()->first(); tree; tree = m_tree->children()->next()) hlist->append( tree->widget()); hlist->sort(); // First we need to make sure that two widgets won't be in the same row, // ie that no widget overlap another one if(!testOnly) { for(WidgetListIterator it(*vlist); it.current() != 0; ++it) { QWidget *w = it.current(); WidgetListIterator it2 = it; for(; it2.current() != 0; ++it2) { QWidget *nextw = it2.current(); if((w->y() >= nextw->y()) || (nextw->y() >= w->geometry().bottom())) break; if(!w->geometry().intersects(nextw->geometry())) break; // If the geometries of the two widgets intersect each other, // we move one of the widget to the rght or bottom of the other if((nextw->y() - w->y()) > abs(nextw->x() - w->x())) nextw->move(nextw->x(), w->geometry().bottom()+1); else if(nextw->x() >= w->x()) nextw->move(w->geometry().right()+1, nextw->y()); else w->move(nextw->geometry().right()+1, nextw->y()); } } } // Then we count the number of rows in the layout, and set their beginnings for(WidgetListIterator it(*vlist); it.current() != 0; ++it) { QWidget *w = it.current(); WidgetListIterator it2 = it; if(!same) { // this widget will make a new row end = w->geometry().bottom(); rows.append(w->y()); } // If same == true, it means we are in the same row as prev widget // (so no need to create a new column) ++it2; if(!it2.current()) break; QWidget *nextw = it2.current(); if(nextw->y() >= end) same = false; else { same = !(same && (nextw->y() >= w->geometry().bottom())); if(!same) end = w->geometry().bottom(); } } kdDebug() << "the new grid will have n rows: n == " << rows.size() << endl; end = -10000; same = false; // We do the same thing for the columns for(WidgetListIterator it(*hlist); it.current() != 0; ++it) { QWidget *w = it.current(); WidgetListIterator it2 = it; if(!same) { end = w->geometry().right(); cols.append(w->x()); } ++it2; if(!it2.current()) break; QWidget *nextw = it2.current(); if(nextw->x() >= end) same = false; else { same = !(same && (nextw->x() >= w->geometry().right())); if(!same) end = w->geometry().right(); } } kdDebug() << "the new grid will have n columns: n == " << cols.size() << endl; // We create the layout .. QGridLayout *layout=0; if(!testOnly) { layout = new QGridLayout(m_container, rows.size(), cols.size(), m_margin, m_spacing, "grid"); m_layout = (QLayout*)layout; } // .. and we fill it with widgets for(WidgetListIterator it(*vlist); it.current() != 0; ++it) { QWidget *w = it.current(); QRect r = w->geometry(); uint wcol=0, wrow=0, endrow=0, endcol=0; uint i = 0; // We look for widget row(s) .. while(r.y() >= rows[i]) { if(rows.size() <= i+1) // we are the last row { wrow = i; break; } if(r.y() < rows[i+1]) { wrow = i; // the widget will be in this row uint j = i + 1; // Then we check if the widget needs to span multiple rows while(rows.size() >= j+1 && r.bottom() > rows[j]) { endrow = j; j++; } break; } i++; } //kdDebug() << "the widget " << w->name() << " wil be in the row " << wrow << //" and will go to the row " << endrow << endl; // .. and column(s) i = 0; while(r.x() >= cols[i]) { if(cols.size() <= i+1) // last column { wcol = i; break; } if(r.x() < cols[i+1]) { wcol = i; uint j = i + 1; // Then we check if the widget needs to span multiple columns while(cols.size() >= j+1 && r.right() > cols[j]) { endcol = j; j++; } break; } i++; } //kdDebug() << "the widget " << w->name() << " wil be in the col " << wcol << // " and will go to the col " << endcol << endl; ObjectTreeItem *item = m_form->objectTree()->lookup(w->name()); if(!endrow && !endcol) { if(!testOnly) layout->addWidget(w, wrow, wcol); item->setGridPos(wrow, wcol, 0, 0); } else { if(!endcol) endcol = wcol; if(!endrow) endrow = wrow; if(!testOnly) layout->addMultiCellWidget(w, wrow, endrow, wcol, endcol); item->setGridPos(wrow, wcol, endrow-wrow+1, endcol-wcol+1); } } } QString Container::layoutTypeToString(int type) { switch(type) { case HBox: return "HBox"; case VBox: return "VBox"; case Grid: return "Grid"; case HFlow: return "HFlow"; case VFlow: return "VFlow"; default: return "NoLayout"; } } Container::LayoutType Container::stringToLayoutType(const QString &name) { if(name == "HBox") return HBox; if(name == "VBox") return VBox; if(name == "Grid") return Grid; if(name == "HFlow") return HFlow; if(name == "VFlow") return VFlow; return NoLayout; } /// Drawing functions used by eventFilter void Container::drawConnection(QMouseEvent *mev) { if(mev->button() != LeftButton) { FormManager::self()->resetCreatedConnection(); return; } // First click, we select the sender and display menu to choose signal if(FormManager::self()->createdConnection()->sender().isNull()) { FormManager::self()->createdConnection()->setSender(m_moving->name()); if(m_form->formWidget()) { m_form->formWidget()->initBuffer(); m_form->formWidget()->highlightWidgets(m_moving, 0/*, QPoint()*/); } FormManager::self()->createSignalMenu(m_moving); return; } // the user clicked outside the menu, we cancel the connection if(FormManager::self()->createdConnection()->signal().isNull()) { FormManager::self()->stopCreatingConnection(); return; } // second click to choose the receiver if(FormManager::self()->createdConnection()->receiver().isNull()) { FormManager::self()->createdConnection()->setReceiver(m_moving->name()); FormManager::self()->createSlotMenu(m_moving); m_container->repaint(); return; } // the user clicked outside the menu, we cancel the connection if(FormManager::self()->createdConnection()->slot().isNull()) { FormManager::self()->stopCreatingConnection(); return; } } void Container::drawSelectionRect(QMouseEvent *mev) { //finish drawing unclipped selection rectangle: clear the surface if(m_form->formWidget()) m_form->formWidget()->clearForm(); int topx = (m_insertBegin.x() < mev->x()) ? m_insertBegin.x() : mev->x(); int topy = (m_insertBegin.y() < mev->y()) ? m_insertBegin.y() : mev->y(); int botx = (m_insertBegin.x() > mev->x()) ? m_insertBegin.x() : mev->x(); int boty = (m_insertBegin.y() > mev->y()) ? m_insertBegin.y() : mev->y(); QRect r = QRect(QPoint(topx, topy), QPoint(botx, boty)); setSelectedWidget(m_container, false); QWidget *widgetToSelect = 0; // We check which widgets are in the rect and select them for(ObjectTreeItem *item = m_tree->children()->first(); item; item = m_tree->children()->next()) { QWidget *w = item->widget(); if(!w) continue; if(w->geometry().intersects(r) && w != m_container) { if (widgetToSelect) setSelectedWidget(widgetToSelect, true/*add*/, false/*raise*/, true/*moreWillBeSelected*/); widgetToSelect = w; //select later } } if (widgetToSelect) //the last one left setSelectedWidget(widgetToSelect, true/*add*/, false/*raise*/, false/*!moreWillBeSelected*/); m_insertRect = QRect(); m_state = DoingNothing; m_container->repaint(); } void Container::drawInsertRect(QMouseEvent *mev, QObject *s) { int tmpx, tmpy; QPoint pos = static_cast(s)->mapTo(m_container, mev->pos()); int gridX = m_form->gridSize(); int gridY = m_form->gridSize(); if(!FormManager::self()->snapWidgetsToGrid() || (mev->state() == (LeftButton|ControlButton|AltButton)) ) { tmpx = pos.x(); tmpy = pos.y(); } else { tmpx = int( (float) pos.x() / ((float)gridX) + 0.5); tmpx *= gridX; tmpy = int( (float)pos.y() / ((float)gridY) + 0.5); tmpy *= gridX; } int topx = (m_insertBegin.x() < tmpx) ? m_insertBegin.x() : tmpx; int topy = (m_insertBegin.y() < tmpy) ? m_insertBegin.y() : tmpy; int botx = (m_insertBegin.x() > tmpx) ? m_insertBegin.x() : tmpx; int boty = (m_insertBegin.y() > tmpy) ? m_insertBegin.y() : tmpy; m_insertRect = QRect(QPoint(topx, topy), QPoint(botx, boty)); if(m_insertRect.x() < 0) m_insertRect.setLeft(0); if(m_insertRect.y() < 0) m_insertRect.setTop(0); if(m_insertRect.right() > m_container->width()) m_insertRect.setRight(m_container->width()); if(m_insertRect.bottom() > m_container->height()) m_insertRect.setBottom(m_container->height()); if(FormManager::self()->isInserting() && m_insertRect.isValid()) { if(m_form->formWidget()) { QRect drawRect = QRect(m_container->mapTo(m_form->widget(), m_insertRect.topLeft()) , m_insertRect.size()); m_form->formWidget()->drawRect(drawRect, 2); } } } void Container::drawCopiedWidgetRect(QMouseEvent *mev) { // We've been dragging a widget, but Ctrl was hold, so we start copy if(m_state == MovingWidget) { //FormManager::self()->undo(); // undo last moving //m_moving->move(m_initialPos); if(m_form->formWidget()) { m_container->repaint(); m_form->formWidget()->initBuffer(); } m_state = CopyingWidget; } //m_copyRect.moveTopLeft(m_container->mapFromGlobal( mev->globalPos()) - m_grab); if(m_form->formWidget()) { QValueList rectList; for(QWidget *w = m_form->selectedWidgets()->first(); w; w = m_form->selectedWidgets()->next()) { QRect drawRect = w->geometry(); QPoint p = mev->pos() - m_grab; drawRect.moveBy(p.x(), p.y()); p = m_container->mapTo(m_form->widget(), QPoint(0, 0)); //drawRect = QRect( ((QWidget*)s)->mapTo(m_form->widget(), drawRect.topLeft()), drawRect.size()); drawRect.moveBy(p.x(), p.y()); rectList.append(drawRect); } m_form->formWidget()->drawRects(rectList, 2); } } /// Other functions used by eventFilter void Container::moveSelectedWidgetsBy(int realdx, int realdy, QMouseEvent *mev) { if (m_form->selectedWidget() == m_form->widget()) return; //do not move top-level widget const int gridX = m_form->gridSize(); const int gridY = m_form->gridSize(); int dx=realdx, dy=realdy; for(QWidget *w = m_form->selectedWidgets()->first(); w; w = m_form->selectedWidgets()->next()) { if(!w || !w->parent() || w->parent()->inherits("QTabWidget") || w->parent()->inherits("QWidgetStack")) continue; if(w->parentWidget() && w->parentWidget()->isA("QWidgetStack")) { w = w->parentWidget(); // widget is WidgetStack page if(w->parentWidget() && w->parentWidget()->inherits("QTabWidget")) // widget is tabwidget page w = w->parentWidget(); } int tmpx = w->x() + realdx; int tmpy = w->y() + realdy; if(tmpx < 0) dx = QMAX(0 - w->x(), dx); // because dx is <0 else if(tmpx > w->parentWidget()->width() - gridX) dx = QMIN(w->parentWidget()->width() - gridX - w->x(), dx); if(tmpy < 0) dy = QMAX(0 - w->y(), dy); // because dy is <0 else if(tmpy > w->parentWidget()->height() - gridY) dy = QMIN(w->parentWidget()->height() - gridY - w->y(), dy); } for(QWidget *w = m_form->selectedWidgets()->first(); w; w = m_form->selectedWidgets()->next()) { // Don't move tab widget pages (or widget stack pages) if(!w || !w->parent() || w->parent()->inherits("QTabWidget") || w->parent()->inherits("QWidgetStack")) continue; if(w->parentWidget() && w->parentWidget()->isA("QWidgetStack")) { w = w->parentWidget(); // widget is WidgetStack page if(w->parentWidget() && w->parentWidget()->inherits("QTabWidget")) // widget is tabwidget page w = w->parentWidget(); } int tmpx, tmpy; if(!FormManager::self()->snapWidgetsToGrid() || (mev && mev->state() == (LeftButton|ControlButton|AltButton)) ) { tmpx = w->x() + dx; tmpy = w->y() + dy; } else { tmpx = int( float( w->x() + dx) / float(gridX) + 0.5) * gridX; tmpy = int( float( w->y() + dy) / float(gridY) + 0.5) * gridY; } if((tmpx != w->x()) || (tmpy != w->y())) w->move(tmpx,tmpy); } } //////////// DesignTimeDynamicChildWidgetHandler::DesignTimeDynamicChildWidgetHandler() : m_item(0) { } DesignTimeDynamicChildWidgetHandler::~DesignTimeDynamicChildWidgetHandler() { } void DesignTimeDynamicChildWidgetHandler::childWidgetAdded(QWidget* w) { if (m_item) { installRecursiveEventFilter(w, m_item->eventEater()); } } #include "container.moc"