From f8f3dae11294508355ca024cacb966f129c1c85c Mon Sep 17 00:00:00 2001 From: Christian Klinger Date: Mon, 2 May 2016 16:16:29 +0200 Subject: better behaviour when placing a client symbol on top of another. --- src/server/mainwindow/mainwindow.cpp | 178 ++++++++++++++++++++++------------- 1 file changed, 111 insertions(+), 67 deletions(-) (limited to 'src/server/mainwindow/mainwindow.cpp') diff --git a/src/server/mainwindow/mainwindow.cpp b/src/server/mainwindow/mainwindow.cpp index 9f667a6..32d5186 100644 --- a/src/server/mainwindow/mainwindow.cpp +++ b/src/server/mainwindow/mainwindow.cpp @@ -38,6 +38,8 @@ #include "ui_mainwindow.h" #include "ui_reloadroom.h" +#include + #define sStrTutorNdef MainWindow::tr("No tutor defined.") #define sStrTutorOffline MainWindow::tr("Tutor is offline.") #define sStrSourceNdef MainWindow::tr("Please select a projection source.") @@ -48,6 +50,8 @@ #define sStrClientOnline MainWindow::tr("Selected client is currently online.") #define sStrNoDestAv MainWindow::tr("No projection destination available.") +using std::vector; + /***************************************************************************//** * Initialize MainWindow and ListenServer. * @param ipListUrl @@ -165,57 +169,77 @@ MainWindow::~MainWindow() delete ui; } +/** Euclidean distance (why is this not implemented in QPoint?) */ +float distance(QPoint a, QPoint b) { + int dx = a.x() - b.x(); + int dy = a.y() - b.y(); + int sum = dx*dx + dy*dy; + return sqrt((float) sum); +} /***************************************************************************//** - * Place the frames at possible Position. - * If current position out of range, place frame into next free cell. + * Place the frame into a free position that is closest (Euclidean distance) to + * the preferred point. + * + * If current position out of range, place frame into the closest free cell. + * 'Algorithm': ideally, go in circles around the preferred point until you find + * a free spot. Lazy way: store all free positions in an array and find later + * there the closest (<- that's what I do) + * * @param frame */ -void MainWindow::placeFrameInFreeSlot(ConnectionFrame* frame) +void MainWindow::placeFrameInFreeSlot(ConnectionFrame* frame, QPoint preferred) { - // Get occupied cell of each frame and store status in an array - const int elems = _tilesX * _tilesY; - int currentIndex = 0; - bool grid[elems]; - memset(grid, 0, sizeof(bool) * elems); // set everything to false + qDebug() << "placeFrameInFreeSlot(preferred = " << preferred << ")"; + const QSize& clientSize = Global::getRooms()[Global::getCurrentRoom()]->clientSize; + /* Get occupied cell of each frame and store status in an array */ + bool grid[_tilesX][_tilesY]; + memset(grid, 0, sizeof(bool) * _tilesX * _tilesY); // set everything to false + + /* fill grid */ for (QList::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it) { - const QPoint &oldpos = (*it)->frameGeometry().topLeft(); - const int tx = oldpos.x() / getTileWidthPx(); - const int ty = oldpos.y() / getTileHeightPx(); - const int index = tx + ty * _tilesX; - if (frame == *it) - { - // Current frame is the frame to place, remember its old index - currentIndex = index; - continue; - } - if (index < 0 || index >= elems) - { - // Current frame is out of bounds, place in top left corner - qDebug("Move A"); - (*it)->move(0, 0); - grid[0] = true; - continue; - } - // Just mark cell as occupied in array - grid[index] = true; - } - // Safety - if (currentIndex < 0 || currentIndex >= elems) - currentIndex = 0; - // Now place in next free cell, start looking at current position of frame - for (int i = 0; i < elems; ++i) - { - const int index = (i + currentIndex) % elems; - if (grid[index]) - continue; - const int x = (index % _tilesX) * getTileWidthPx(); - const int y = (index / _tilesX) * getTileHeightPx(); - //qDebug() << "Index=" << index << " i=" << i << " cI=" << currentIndex << " elems=" << elems << " x=" << x << " y=" << y; - qDebug("Move B"); - frame->move(x, y); - break; - } + const QPoint& position = (*it)->getGridPosition(); + + for (int x = position.x(); x < position.x() + clientSize.width(); x++) { + for (int y = position.y(); y < position.y() + clientSize.height(); y++) { + grid[x][y] = true; + } + } + } + + /* Now place in next free cell, start looking at current position of frame */ + vector freePositions; + for (int x = 0; x < _tilesX - clientSize.width(); x++) { + for ( int y = 0; y < _tilesY - clientSize.height(); y++) { + /* check if (x,y) is free */ + bool isFree = true; + for (int dx = 0; dx < clientSize.width(); dx++) { + for (int dy = 0; dy < clientSize.width(); dy++) { + if (grid[x + dx][y + dy]) { + isFree = false; + } + } + } + if (isFree) { + QPoint freePos(x,y); + freePositions.push_back(freePos); + } + } + } + /* among all the free positions, find the closest */ + float min_distance = 10000; + QPoint bestPosition = QPoint(-1, -1); + + for (QPoint freePos : freePositions) { + float dist = distance(freePos, preferred); + if (dist < min_distance) { + min_distance = dist; + bestPosition = freePos; + } + } + frame->setGridPosition(bestPosition); + QPoint freePosPx(bestPosition.x() * getTileWidthPx(), bestPosition.y() * getTileHeightPx()); + frame->setCurrentPosition(freePosPx); } /***************************************************************************//** @@ -227,7 +251,10 @@ void MainWindow::placeFrameInFreeSlot(ConnectionFrame* frame) ConnectionFrame* MainWindow::createFrame() { // Allocate and resize - ConnectionFrame *cf = new ConnectionFrame(ui->frmRoom, getTileWidthPx(), getTileHeightPx()); + int width = getTileWidthPx() * Global::getRooms()[Global::getCurrentRoom()]->clientSize.width(); + int height= getTileHeightPx() * Global::getRooms()[Global::getCurrentRoom()]->clientSize.height(); + + ConnectionFrame *cf = new ConnectionFrame(ui->frmRoom, width, height); _clientFrames.append(cf); cf->show(); connect(cf, SIGNAL(frameMoved(bool, ConnectionFrame *)), this, SLOT(onPlaceFrame(bool, ConnectionFrame *))); @@ -647,45 +674,60 @@ void MainWindow::reset() */ void MainWindow::onTutorListDownloaded(QByteArray& tutorList) { - // qDebug() << tutorList; QString data = QString::fromUtf8(tutorList.constData(), tutorList.size()); _tutorList = data.split(QRegExp("[\r\n]"),QString::SkipEmptyParts); qDebug() << _tutorList; } + /***************************************************************************//** - * Place Frame to from user specified position. - * @param frame +* Place Frame to from user specified position. +* Behaviour: If placed exactly on another frame: replace that frame and place it +* on the closest free slot. Otherwise: place connectionFrame on the closest free +* slot. */ -void MainWindow::onPlaceFrame(bool activateTrash, ConnectionFrame* frame) +void MainWindow::onPlaceFrame(bool activateTrash, ConnectionFrame* connectionFrame) { if (_tilesX <= 0 || _tilesY <= 0) return; - const QPoint &p = frame->frameGeometry().center(); - const QSize &s = ui->frmRoom->geometry().size(); - int x = (p.x() / getTileWidthPx()) * getTileWidthPx(); - int y = (p.y() / getTileHeightPx()) * getTileHeightPx(); + const QPoint &p = connectionFrame->frameGeometry().center(); + const QSize &s = ui->frmRoom->geometry().size(); + /* round to grid */ + int x = p.x() / getTileWidthPx(); + int y = p.y() / getTileHeightPx(); if (x < 0) x = 0; else if (x > s.width() - getTileWidthPx()) - x = (_tilesX - 1) * getTileWidthPx(); + x = (_tilesX - 1); if (y < 0) y = 0; else if (y > s.height() - getTileHeightPx()) - y = (_tilesY - 1) * getTileHeightPx(); - - frame->move(x, y); - savePosition(frame); - const QPoint &newpos = frame->frameGeometry().topLeft(); - for (QList::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it) - { - if (*it == frame) - continue; - if ((*it)->frameGeometry().topLeft() == newpos) - { - placeFrameInFreeSlot(*it); + y = (_tilesY - 1); + /* --- */ + + QPoint newPos(x,y); + connectionFrame->setGridPosition(newPos); + placeFrameInFreeSlot(connectionFrame, newPos); + + /* if there is already a frame at that position, push it away */ + bool replacedFrame = false; + for (auto it = _clientFrames.begin(); it != _clientFrames.end(); ++it) { + if (*it == connectionFrame) { continue; } + + if ((*it)->getGridPosition() == newPos) { + connectionFrame->setGridPosition(newPos); + placeFrameInFreeSlot(*it, newPos); /* place frame in free slot, close to newPos */ + replacedFrame = true; + break; } } + if (!replacedFrame) { + placeFrameInFreeSlot(connectionFrame, newPos); + } + /* update positions */ + + savePosition(connectionFrame); /* save in local config to remember position */ + resizeEvent(NULL); } /***************************************************************************//** @@ -1258,7 +1300,9 @@ void MainWindow::onClientAuthenticated(Client* client) // Assign client instance cf->assignClient(client); + resizeEvent(NULL); // This is where all the positioning should be tellClientCurrentSituation(client); + } /***************************************************************************//** -- cgit v1.2.3-55-g7522