aboutsummaryrefslogtreecommitdiff
path: root/src-qt5/core/lumina-desktop-unified
diff options
context:
space:
mode:
authorKen Moore <ken@ixsystems.com>2018-06-05 12:16:08 -0400
committerKen Moore <ken@ixsystems.com>2018-06-05 12:16:08 -0400
commit4b303bd5dfcb49c6be0e9e1607134b21de8fbf1a (patch)
tree506340fbaeebe7ad35c6a9f1e898d1377fb3b999 /src-qt5/core/lumina-desktop-unified
parentFix up the window frame borders. (diff)
downloadlumina-4b303bd5dfcb49c6be0e9e1607134b21de8fbf1a.tar.gz
lumina-4b303bd5dfcb49c6be0e9e1607134b21de8fbf1a.tar.bz2
lumina-4b303bd5dfcb49c6be0e9e1607134b21de8fbf1a.zip
Get the window movement working, and mouse cursor changes on mouseover working as well.
Resizing a window will crash things at the moment - still looking into that...
Diffstat (limited to 'src-qt5/core/lumina-desktop-unified')
-rw-r--r--src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/NativeEmbedWidget.h3
-rw-r--r--src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/NativeWindow.cpp292
-rw-r--r--src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/NativeWindow.h25
3 files changed, 319 insertions, 1 deletions
diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/NativeEmbedWidget.h b/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/NativeEmbedWidget.h
index f9cc52b7..73f4e908 100644
--- a/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/NativeEmbedWidget.h
+++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/NativeEmbedWidget.h
@@ -40,9 +40,10 @@ public:
~NativeEmbedWidget(){}
QWidget* widget(){ return embedW; }
+ QRect geometry(){ return embedW->geometry(); }
public slots:
- void activateWindow(){ _window->requestActivate(); }
+ void activateWindow(){ QTimer::singleShot(0, _window, SLOT(requestActivate())); }
};
diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/NativeWindow.cpp b/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/NativeWindow.cpp
index b7909da1..3c4562c1 100644
--- a/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/NativeWindow.cpp
+++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/NativeWindow.cpp
@@ -13,6 +13,12 @@
NativeWindow::NativeWindow( NativeWindowObject *obj ) : QFrame(0, Qt::Window | Qt::FramelessWindowHint){
WIN = obj;
createFrame();
+ this->setMouseTracking(true);
+ //Setup the timer object to syncronize info
+ moveTimer = new QTimer(this);
+ moveTimer->setSingleShot(true);
+ moveTimer->setInterval(100); //1/10 second
+ connect(moveTimer, SIGNAL(timeout()), this, SLOT(syncGeom()) );
//WIN->addFrameWinID(this->winId());
}
@@ -60,21 +66,157 @@ void NativeWindow::initProperties(){
container->activateWindow();
}
+//Mouse Interactivity
+void NativeWindow::startMoving(){
+ //If the cursor is not over this window, move it to the center of the titlebar
+ QPoint curpt = QCursor::pos(); //global coords
+ if(!this->geometry().contains(curpt)){
+ curpt = this->mapToGlobal(titleLabel->geometry().center());
+ QCursor::setPos(curpt);
+ }
+ //Calculate the offset
+ activeState = Move;
+ offset = this->mapFromGlobal(curpt);
+ setMouseCursor(activeState, true); //this one is an override cursor
+ //WinWidget->pause();
+ this->grabMouse();
+}
+
+void NativeWindow::startResizing(){
+ activeState = getStateAtPoint( this->mapFromGlobal(QCursor::pos()), true); //also have it set the offset variable
+ setMouseCursor(activeState, true); //this one is an override cursor
+ //WinWidget->pause();
+ this->grabMouse();
+}
+
// === PRIVATE ===
+NativeWindow::ModState NativeWindow::getStateAtPoint(QPoint pt, bool setoffset){
+ //Note: pt should be in widget-relative coordinates, not global
+ QList<int> frame = WIN->property(NativeWindowObject::FrameExtents).value<QList<int> >();
+ /*QList<int> : [Left, Right, Top, Bottom] in pixels */
+ bool onLeft = (pt.x()<=frame[0]);
+ bool onRight = (pt.x() >= (this->width()-frame[1])) && pt.x() <= this->width();
+ bool onTop = (pt.y() < titleLabel->y() ); //be careful about this one - the top frame gets split up and the title bar put in
+ bool onBottom = (pt.y() >= (this->height()-frame[3]) && (pt.y() <= this->height()) );
+ if(onLeft || onRight || onTop || onBottom){
+ //above the frame itself - need to figure out which quadrant it is in (8-directions)
+ if(onTop){
+ //One of the top options
+ if(onLeft){
+ if(setoffset){ offset.setX(pt.x()); offset.setY(pt.y()); } //difference from top-left corner
+ return ResizeTopLeft;
+ }else if(onRight){
+ if(setoffset){ offset.setX(pt.x()-this->width()); offset.setY(pt.y()); } //difference from top-right corner
+ return ResizeTopRight;
+ }else{
+ if(setoffset){ offset.setX(0); offset.setY(pt.y()); } //difference from top edge (X does not matter)
+ return ResizeTop;
+ }
+ }else if(onBottom){
+ //One of the bottom options
+ if(onLeft){
+ if(setoffset){ offset.setX(pt.x()); offset.setY(pt.y()-this->height()); } //difference from bottom-left corner
+ return ResizeBottomLeft;
+ }else if(onRight){
+ if(setoffset){ offset.setX(pt.x()-this->width()); offset.setY(pt.y()-this->height()); } //difference from bottom-right corner
+ return ResizeBottomRight;
+ }else{
+ if(setoffset){ offset.setX(0); offset.setY(pt.y()-this->height()); } //difference from bottom edge (X does not matter)
+ return ResizeBottom;
+ }
+ }else if(onLeft){
+ //Left side options
+ /*if(pt.y() < this->height()/5){
+ if(setoffset){ offset.setX(pt.x()); offset.setY(pt.y()); } //difference from top-left corner
+ return ResizeTopLeft;
+ }else if(pt.y() > (this->height()*4.0/5.0)){
+ if(setoffset){ offset.setX(pt.x()); offset.setY(pt.y()-this->height()); } //difference from bottom-left corner
+ return ResizeBottomLeft;
+ }else{*/
+ if(setoffset){ offset.setX(pt.x()); offset.setY(0); } //difference from left edge (Y does not matter)
+ return ResizeLeft;
+ //}
+ }else if(onRight){
+ //Right side options
+ /*if(pt.y() < this->height()/5){
+ if(setoffset){ offset.setX(pt.x()-this->width()); offset.setY(pt.y()); } //difference from top-right corner
+ return ResizeTopRight;
+ }else if(pt.y() > (this->height()*4.0/5.0)){
+ if(setoffset){ offset.setX(pt.x()-this->width()); offset.setY(pt.y()-this->height()); } //difference from bottom-right corner
+ return ResizeBottomRight;
+ }else{*/
+ if(setoffset){ offset.setX(pt.x()-this->width()); offset.setY(0); } //difference from right edge (Y does not matter)
+ return ResizeRight;
+ //}
+ }else{
+ return Normal;
+ }
+ }
+ //if it gets this far just return normal
+ return Normal;
+}
+
+void NativeWindow::setMouseCursor(ModState state, bool override){
+ if(currentCursor==state && !override){ return; } //nothing to change
+ Qt::CursorShape shape;
+ switch(state){
+ case Normal:
+ shape = Qt::ArrowCursor;
+ break;
+ case Move:
+ shape = Qt::SizeAllCursor;
+ break;
+ case ResizeTop:
+ shape = Qt::SizeVerCursor;
+ break;
+ case ResizeTopRight:
+ shape = Qt::SizeBDiagCursor;
+ break;
+ case ResizeRight:
+ shape = Qt::SizeHorCursor;
+ break;
+ case ResizeBottomRight:
+ shape = Qt::SizeFDiagCursor;
+ break;
+ case ResizeBottom:
+ shape = Qt::SizeVerCursor;
+ break;
+ case ResizeBottomLeft:
+ shape = Qt::SizeBDiagCursor;
+ break;
+ case ResizeLeft:
+ shape = Qt::SizeHorCursor;
+ break;
+ case ResizeTopLeft:
+ shape = Qt::SizeFDiagCursor;
+ break;
+ }
+ if(override){
+ QApplication::setOverrideCursor(QCursor(shape));
+ }else{
+ currentCursor = state;
+ this->setCursor(shape);
+ }
+}
+
void NativeWindow::createFrame(){
//Initialize the widgets
closeB = new QToolButton(this);
closeB->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
closeB->setAutoRaise(true);
+ closeB->setCursor(Qt::ArrowCursor);
minB = new QToolButton(this);
minB->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
minB->setAutoRaise(true);
+ minB->setCursor(Qt::ArrowCursor);
maxB = new QToolButton(this);
maxB->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
maxB->setAutoRaise(true);
+ maxB->setCursor(Qt::ArrowCursor);
otherB = new QToolButton(this);
otherB->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
otherB->setAutoRaise(true);
+ otherB->setCursor(Qt::ArrowCursor);
vlayout = new QVBoxLayout();
vlayout->setSpacing(0);
toolbarL = new QHBoxLayout();
@@ -85,6 +227,7 @@ void NativeWindow::createFrame(){
//vlayout.align
titleLabel = new QLabel(this);
titleLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ titleLabel->setCursor(Qt::ArrowCursor);
//Now put the widgets in the right places
toolbarL->addWidget(otherB);
toolbarL->addWidget(titleLabel);
@@ -169,3 +312,152 @@ void NativeWindow::syncGeom(){
this->setGeometry( geom );
}
}
+
+// === PROTECTED ===
+void NativeWindow::mousePressEvent(QMouseEvent *ev){
+ container->activateWindow();
+ this->raise();
+ QFrame::mousePressEvent(ev);
+ //qDebug() << "Frame Mouse Press Event";
+ if(activeState != Normal){ return; } // do nothing - already in a state of grabbed mouse
+ offset.setX(0); offset.setY(0);
+ if(ev->button()==Qt::LeftButton){
+ if(this->childAt(ev->pos())!=0){
+ //Clicked on the titlebar
+ startMoving();
+ }else{
+ //Clicked on the frame somewhere
+ startResizing();
+ }
+ }
+
+}
+
+void NativeWindow::mouseMoveEvent(QMouseEvent *ev){
+ QFrame::mouseMoveEvent(ev);
+ if(activeState == Normal){
+ setMouseCursor( getStateAtPoint(ev->pos()) ); //just update the mouse cursor
+ }else{
+ //Currently in a modification state
+ QRect geom = this->geometry();
+ QList<int> frame = WIN->property(NativeWindowObject::FrameExtents).value<QList<int> >();
+ /*QList<int> : [Left, Right, Top, Bottom] in pixels */
+ QSize minsize(container->widget()->minimumSize().width() + frame[0]+frame[1], container->widget()->minimumSize().height()+frame[2]+frame[3] );
+ switch(activeState){
+ case Move:
+ geom.moveTopLeft(ev->globalPos()-offset); //will not change size
+ break;
+ case ResizeTop:
+ geom.setTop(ev->globalPos().y()-offset.y());
+ if(geom.size().height() < minsize.height()){
+ geom.setTop(geom.y() - (minsize.height()-geom.size().height())); //reset back to min height
+ }
+ break;
+ case ResizeTopRight:
+ geom.setTopRight(ev->globalPos()-offset);
+ if(geom.size().height() < minsize.height()){
+ geom.setTop(geom.y() - (minsize.height()-geom.size().height())); //reset back to min height
+ }
+ if(geom.size().width() < minsize.width()){
+ geom.setRight(geom.x() + minsize.width()); //reset back to min width
+ }
+ break;
+ case ResizeRight:
+ geom.setRight(ev->globalPos().x()-offset.x());
+ if(geom.size().width() < minsize.width()){
+ geom.setRight(geom.x() + minsize.width()); //reset back to min width
+ }
+ break;
+ case ResizeBottomRight:
+ geom.setBottomRight(ev->globalPos()-offset);
+ if(geom.size().height() < minsize.height()){
+ geom.setBottom(geom.y() + minsize.height()); //reset back to min height
+ }
+ if(geom.size().width() < minsize.width()){
+ geom.setRight(geom.x() + minsize.width()); //reset back to min width
+ }
+ break;
+ case ResizeBottom:
+ geom.setBottom(ev->globalPos().y()-offset.y());
+ if(geom.size().height() < minsize.height()){
+ geom.setBottom(geom.y() + minsize.height()); //reset back to min height
+ }
+ break;
+ case ResizeBottomLeft:
+ geom.setBottomLeft(ev->globalPos()-offset);
+ if(geom.size().height() < minsize.height()){
+ geom.setBottom(geom.y() + minsize.height()); //reset back to min height
+ }
+ if(geom.size().width() < minsize.width()){
+ geom.setLeft(geom.x() - (minsize.width()-geom.size().width())); //reset back to min width
+ }
+ break;
+ case ResizeLeft:
+ geom.setLeft(ev->globalPos().x()-offset.x());
+ if(geom.size().width() < minsize.width()){
+ geom.setLeft(geom.x() - (minsize.width()-geom.size().width())); //reset back to min width
+ }
+ break;
+ case ResizeTopLeft:
+ geom.setTopLeft(ev->globalPos()-offset);
+ if(geom.size().height() < minsize.height()){
+ geom.setTop(geom.y() - (minsize.height()-geom.size().height())); //reset back to min height
+ }
+ if(geom.size().width() < minsize.width()){
+ geom.setLeft(geom.x() - (minsize.width()-geom.size().width())); //reset back to min width
+ }
+ break;
+ default:
+ break;
+ }
+ //if( (geom.width()%2==0 && geom.height()%2==0) || activeState==Move){
+ //qDebug() << " Change Window:" << this->geometry() << geom;
+ if(activeState==Move){ this->setGeometry(geom); }
+ else{
+ //qDebug() << " Change Window Dimensions:" << this->geometry() << geom;
+ //qDebug() << " - Mouse Pos:" << ev->globalPos() << ev->pos() << "Offset" << offset;
+ this->setGeometry(geom);
+ }
+ //}
+ }
+}
+
+void NativeWindow::mouseReleaseEvent(QMouseEvent *ev){
+ //Check for a right-click event
+ //qDebug() << "Frame Mouse Release Event";
+ QFrame::mouseReleaseEvent(ev);
+ if( (activeState==Normal) && (titleLabel->geometry().contains(ev->pos())) && (ev->button()==Qt::RightButton) ){
+ //container->raiseWindow();//need to ensure the native window is always on top of this frame but under the menu
+ otherB->emit clicked();
+ return;
+ }
+ if(activeState!=Normal){
+ //if(container->isPaused()){ container->resume(); }
+ activeState = Normal;
+ QApplication::restoreOverrideCursor();
+ setMouseCursor( getStateAtPoint(ev->pos()) );
+ }
+ if(QFrame::mouseGrabber() == this){ this->releaseMouse(); }
+ container->activateWindow();
+ //QTimer::singleShot(0, container, SLOT(raiseWindow()) );
+}
+
+/*void NativeWindow::enterEvent(QEvent *ev){
+ QFrame::enterEvent(ev);
+ container->raiseWindow();
+}*/
+void NativeWindow::leaveEvent(QEvent *ev){
+ QFrame::leaveEvent(ev);
+ if(activeState == Normal){
+ setMouseCursor(Normal);
+ }
+ //if(!QRect(QPoint(0,0),this->size()).contains( this->mapFromGlobal(QCursor::pos())) ){ container->lowerWindow(); }
+}
+
+void NativeWindow::moveEvent(QMoveEvent *ev){
+ //qDebug() << "Got Move Event:" << ev->pos() << container->geometry();
+ QFrame::moveEvent(ev);
+ //if(!closing && !container->isPaused()){
+ moveTimer->start();
+ //}
+}
diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/NativeWindow.h b/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/NativeWindow.h
index 47699ae6..20491014 100644
--- a/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/NativeWindow.h
+++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/NativeWindow.h
@@ -21,8 +21,21 @@ public:
public slots:
void initProperties();
+ //Mouse Interactivity
+ void startMoving();
+ void startResizing();
private:
+ //Window status
+ enum ModState{Normal, Move, ResizeTop, ResizeTopRight, ResizeRight, ResizeBottomRight, ResizeBottom, ResizeBottomLeft, ResizeLeft, ResizeTopLeft};
+ ModState activeState;
+ ModState currentCursor;
+ QPoint offset; //needed for movement calculations (offset from mouse click to movement point)
+ //Functions for getting/setting state
+ ModState getStateAtPoint(QPoint pt, bool setoffset = false); //generally used for mouse location detection
+ void setMouseCursor(ModState, bool override = false); //Update the mouse cursor based on state
+ QTimer *moveTimer;
+
//Core object
NativeWindowObject *WIN;
// Interface items
@@ -49,6 +62,18 @@ private slots:
void syncVisibility(bool init = false);
void syncWinType();
void syncGeom();
+
+protected:
+ void mousePressEvent(QMouseEvent*);
+ void mouseMoveEvent(QMouseEvent*);
+ void mouseReleaseEvent(QMouseEvent*);
+ void leaveEvent(QEvent *ev);
+ //void enterEvent(QEvent *ev);
+ void moveEvent(QMoveEvent *ev);
+
+signals:
+ void windowMoved(NativeWindowObject*);
+
};
#endif
bgstack15