aboutsummaryrefslogtreecommitdiff
path: root/src-qt5/core/libLumina
diff options
context:
space:
mode:
authorKen Moore <ken@ixsystems.com>2017-03-02 19:28:05 -0500
committerKen Moore <ken@ixsystems.com>2017-03-02 19:28:05 -0500
commit00d95d8a1323a4c0603a7a6f622c1b5cc981d2ce (patch)
tree6b49932d76a45009855acceaae687e153bed0f8f /src-qt5/core/libLumina
parentMerge branch 'master' of github.com:trueos/lumina (diff)
downloadlumina-00d95d8a1323a4c0603a7a6f622c1b5cc981d2ce.tar.gz
lumina-00d95d8a1323a4c0603a7a6f622c1b5cc981d2ce.tar.bz2
lumina-00d95d8a1323a4c0603a7a6f622c1b5cc981d2ce.zip
Write up a new window frame for Lumina2 (not using the QMdi[Sub]Window classes). This seems to be working much better so far - still need to finish filling out the various interaction functions and themeing (stylesheet object names done).
Diffstat (limited to 'src-qt5/core/libLumina')
-rw-r--r--src-qt5/core/libLumina/NativeWindow.cpp5
-rw-r--r--src-qt5/core/libLumina/NativeWindow.h2
-rw-r--r--src-qt5/core/libLumina/RootSubWindow.cpp258
-rw-r--r--src-qt5/core/libLumina/RootSubWindow.h44
4 files changed, 275 insertions, 34 deletions
diff --git a/src-qt5/core/libLumina/NativeWindow.cpp b/src-qt5/core/libLumina/NativeWindow.cpp
index bd42ecaa..bcdc30d0 100644
--- a/src-qt5/core/libLumina/NativeWindow.cpp
+++ b/src-qt5/core/libLumina/NativeWindow.cpp
@@ -35,3 +35,8 @@ void NativeWindow::setProperty(NativeWindow::Property prop, QVariant val){
hash.insert(prop, val);
emit PropertyChanged(prop, val);
}
+
+void NativeWindow::requestProperty(NativeWindow::Property prop, QVariant val){
+ if(prop == NativeWindow::None){ return; }
+ emit RequestPropertyChange(winid, prop, val);
+}
diff --git a/src-qt5/core/libLumina/NativeWindow.h b/src-qt5/core/libLumina/NativeWindow.h
index 59b955c3..03d7e27d 100644
--- a/src-qt5/core/libLumina/NativeWindow.h
+++ b/src-qt5/core/libLumina/NativeWindow.h
@@ -55,6 +55,7 @@ public:
QVariant property(NativeWindow::Property);
void setProperty(NativeWindow::Property, QVariant);
+ void requestProperty(NativeWindow::Property, QVariant);
private:
QHash <NativeWindow::Property, QVariant> hash;
@@ -64,6 +65,7 @@ private:
signals:
//General Notifications
void PropertyChanged(NativeWindow::Property, QVariant);
+ void RequestPropertyChange(WId, NativeWindow::Property, QVariant);
void WindowClosed(WId);
//Action Requests (not automatically emitted - typically used to ask the WM to do something)
diff --git a/src-qt5/core/libLumina/RootSubWindow.cpp b/src-qt5/core/libLumina/RootSubWindow.cpp
index e4c3c4ee..9769c922 100644
--- a/src-qt5/core/libLumina/RootSubWindow.cpp
+++ b/src-qt5/core/libLumina/RootSubWindow.cpp
@@ -6,22 +6,24 @@
//===========================================
#include "RootSubWindow.h"
#include <QDebug>
+#include <QApplication>
+#include <QVBoxLayout>
+#include <QVBoxLayout>
// === PUBLIC ===
-RootSubWindow::RootSubWindow(QMdiArea *root, NativeWindow *win) : QMdiSubWindow(0){
+RootSubWindow::RootSubWindow(QWidget *root, NativeWindow *win) : QFrame(root){
this->setAttribute(Qt::WA_DeleteOnClose);
+ this->setMouseTracking(true);
//Create the QWindow and QWidget containers for the window
WIN = win;
closing = false;
WinWidget = QWidget::createWindowContainer( WIN->window(), this);
- this->setWidget(WinWidget);
+ initWindowFrame();
LoadProperties( QList< NativeWindow::Property>() << NativeWindow::Title << NativeWindow::Icon \
<< NativeWindow::MinSize << NativeWindow::MaxSize << NativeWindow::Size );
//Hookup the signals/slots
connect(this, SIGNAL(aboutToActivate()), this, SLOT(aboutToActivate()) );
connect(WIN, SIGNAL(PropertyChanged(NativeWindow::Property, QVariant)), this, SLOT(propertyChanged(NativeWindow::Property, QVariant)));
- //Now add this window to the root QMdiArea
- root->addSubWindow(this);
//Make sure the visibily property only gets loaded after it is added to the root area
propertyChanged(NativeWindow::Visible, WIN->property(NativeWindow::Visible));
}
@@ -35,6 +37,127 @@ WId RootSubWindow::id(){
}
// === PRIVATE ===
+RootSubWindow::ModState RootSubWindow::getStateAtPoint(QPoint pt, bool setoffset){
+ //Note: pt should be in widget-relative coordinates, not global
+ if(!WinWidget->geometry().contains(pt)){
+ //above the frame itself - need to figure out which quadrant it is in (8-directions)
+ if(pt.y() < 3){
+ //One of the top options
+ if(pt.x() < 3){
+ if(setoffset){ offset.setX(pt.x()); offset.setY(pt.y()); } //difference from top-left corner
+ return ResizeTopLeft;
+ }else if(pt.x() > (this->width()-3)){
+ if(setoffset){ offset.setX(this->width()-pt.x()); 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(pt.y() > (this->height()-3) ){
+ //One of the bottom options
+ if(pt.x() < 3){
+ if(setoffset){ offset.setX(pt.x()); offset.setY(this->height()-pt.y()); } //difference from bottom-left corner
+ return ResizeBottomLeft;
+ }else if(pt.x() > (this->width()-3)){
+ if(setoffset){ offset.setX(this->width()-pt.x()); offset.setY(this->height()-pt.y()); } //difference from bottom-right corner
+ return ResizeBottomRight;
+ }else{
+ if(setoffset){ offset.setX(0); offset.setY(this->height() - pt.y()); } //difference from bottom edge (X does not matter)
+ return ResizeBottom;
+ }
+ }else{
+ //One of the side options
+ if(pt.x() < 3){
+ if(setoffset){ offset.setX(pt.x()); offset.setY(0); } //difference from left edge (Y does not matter)
+ return ResizeLeft;
+ }else if(pt.x() > (this->width()-3) ){
+ if(setoffset){ offset.setX(this->width()-pt.x()); offset.setY(0); } //difference from right edge (Y does not matter)
+ return ResizeRight;
+ }else{
+ return Normal;
+ }
+ }
+ }
+ return Normal;
+}
+
+void RootSubWindow::setMouseCursor(ModState state, bool override){
+ 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{
+ this->setCursor(shape);
+ }
+}
+
+void RootSubWindow::initWindowFrame(){
+ mainLayout = new QVBoxLayout(this);
+ titleBar = new QHBoxLayout(this);
+ closeB = new QToolButton(this);
+ maxB = new QToolButton(this);
+ minB = new QToolButton(this);
+ titleLabel = new QLabel(this);
+ titleLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ otherM = new QMenu(this); //menu of other actions
+ connect(closeB, SIGNAL(clicked()), this, SLOT(triggerClose()) );
+ connect(maxB, SIGNAL(clicked()), this, SLOT(toggleMaximize()) );
+ connect(minB, SIGNAL(clicked()), this, SLOT(toggleMinimize()) );
+ //Now assemble the frame layout based on the current settings
+ this->setLayout(mainLayout);
+ titleBar->addWidget(titleLabel);
+ titleBar->addWidget(minB);
+ titleBar->addWidget(maxB);
+ titleBar->addWidget(closeB);
+ WinWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ mainLayout->addLayout(titleBar);
+ mainLayout->addWidget(WinWidget);
+ //Now all the stylesheet options
+ this->setObjectName("WindowFrame");
+ closeB->setObjectName("Button_Close");
+ minB->setObjectName("Button_Minimize");
+ maxB->setObjectName("Button_Maximize");
+ otherM->setObjectName("Menu_Actions");
+ titleLabel->setObjectName("Label_Title");
+ this->setStyleSheet("QWidget#WindowFrame{background-color: black;} QWidget#Label_Title{background-color: darkgrey; color: white; }");
+ //And adjust the margins
+ mainLayout->setContentsMargins(4,4,4,4);
+ mainLayout->setSpacing(0);
+ titleBar->setSpacing(1);
+ titleBar->setContentsMargins(0,0,0,0);
+}
+
void RootSubWindow::LoadProperties( QList< NativeWindow::Property> list){
for(int i=0; i<list.length(); i++){
propertyChanged( list[i], WIN->property(list[i]) );
@@ -48,19 +171,41 @@ void RootSubWindow::clientClosed(){
this->close();
}
-void RootSubWindow::clientHidden(){
- qDebug() << "Client Hidden";
- this->hide();
+//Button Actions - public so they can be tied to key shortcuts and stuff as well
+void RootSubWindow::toggleMinimize(){
+
+}
+
+void RootSubWindow::toggleMaximize(){
+
+}
+
+void RootSubWindow::triggerClose(){
+ WIN->emit RequestClose(WIN->id());
+}
+
+void RootSubWindow::toggleSticky(){
+
+}
+
+void RootSubWindow::activate(){
+ WIN->emit RequestActivate(WIN->id());
+}
+
+//Mouse Interactivity
+void RootSubWindow::startMoving(){
+
}
-void RootSubWindow::clientShown(){
- qDebug() << "Client Shown";
- this->show();
+void RootSubWindow::startResizing(){
+
}
+
+
// === PRIVATE SLOTS ===
void RootSubWindow::aboutToActivate(){
- WIN->emit RequestActivate(WIN->id());
+
}
void RootSubWindow::propertyChanged(NativeWindow::Property prop, QVariant val){
@@ -68,26 +213,26 @@ void RootSubWindow::propertyChanged(NativeWindow::Property prop, QVariant val){
qDebug() << "Set Window Property:" << prop << val;
switch(prop){
case NativeWindow::Visible:
- if(val.toBool()){ clientShown(); }
- else{ clientHidden(); }
+ if(val.toBool()){ this->show(); }
+ else{ this->hide(); }
break;
case NativeWindow::Title:
- this->setWindowTitle(val.toString());
+ titleLabel->setText(val.toString());
break;
case NativeWindow::Icon:
- this->setWindowIcon(val.value< QIcon>());
+ //this->setWindowIcon(val.value< QIcon>());
break;
case NativeWindow::Size:
- this->resize(val.toSize());
+ WinWidget->resize(val.toSize());
break;
case NativeWindow::MinSize:
- this->setMinimumSize(val.toSize());
+ WinWidget->setMinimumSize(val.toSize());
break;
case NativeWindow::MaxSize:
- this->setMaximumSize(val.toSize());
+ WinWidget->setMaximumSize(val.toSize());
break;
case NativeWindow::Active:
- if(val.toBool()){ this->mdiArea()->setActiveSubWindow(this); }
+ WinWidget->setFocus();
break;
/*case NativeWindow::WindowFlags:
this->setWindowFlags( val.value< Qt::WindowFlags >() );
@@ -98,13 +243,76 @@ void RootSubWindow::propertyChanged(NativeWindow::Property prop, QVariant val){
}
// === PROTECTED ===
-void RootSubWindow::closeEvent(QCloseEvent *ev){
- if(!closing){
- //qDebug() << "Close Window By Button:" << WIN->id();
- ev->ignore();
- WIN->emit RequestClose(WIN->id());
+void RootSubWindow::mousePressEvent(QMouseEvent *ev){
+ qDebug() << "Frame Mouse Press Event";
+ offset.setX(0); offset.setY(0);
+ if(activeState != Normal){ return; } // do nothing - already in a state of grabbed mouse
+ this->activate();
+ if(this->childAt(ev->pos())!=0){
+ //Check for any non-left-click event and skip it
+ if(ev->button()!=Qt::LeftButton){ return; }
+ activeState = Move;
+ offset.setX(ev->pos().x()); offset.setY(ev->pos().y());
}else{
- QMdiSubWindow::closeEvent(ev);
+ //Clicked on the frame somewhere
+ activeState = getStateAtPoint(ev->pos(), true); //also have it set the offset variable
}
+ setMouseCursor(activeState, true); //this one is an override cursor
}
+
+void RootSubWindow::mouseMoveEvent(QMouseEvent *ev){
+ ev->accept();
+ if(activeState == Normal){
+ setMouseCursor( getStateAtPoint(ev->pos()) ); //just update the mouse cursor
+
+ }else{
+ //Currently in a modification state
+ QRect geom = this->geometry();
+ switch(activeState){
+ case Move:
+ geom.moveTopLeft(ev->globalPos()-offset); //will not change size
+ break;
+ case ResizeTop:
+ geom.setTop(ev->globalPos().y()-offset.y());
+ break;
+ case ResizeTopRight:
+ geom.setTopRight(ev->globalPos()-offset);
+ break;
+ case ResizeRight:
+ geom.setRight(ev->globalPos().x()-offset.x());
+ break;
+ case ResizeBottomRight:
+ geom.setBottomRight(ev->globalPos()-offset);
+ break;
+ case ResizeBottom:
+ geom.setBottom(ev->globalPos().y()-offset.y());
+ break;
+ case ResizeBottomLeft:
+ geom.setBottomLeft(ev->globalPos()-offset);
+ break;
+ case ResizeLeft:
+ geom.setLeft(ev->globalPos().x()-offset.x());
+ break;
+ case ResizeTopLeft:
+ geom.setTopLeft(ev->globalPos()-offset);
+ break;
+ default:
+ break;
+ }
+ this->setGeometry(geom);
+ }
+}
+
+void RootSubWindow::mouseReleaseEvent(QMouseEvent *ev){
+ //Check for a right-click event
+ qDebug() << "Frame Mouse Release Event";
+ ev->accept();
+ if( (activeState==Normal) && (titleBar->geometry().contains(ev->pos())) && (ev->button()==Qt::RightButton) ){
+ otherM->popup(ev->globalPos());
+ return;
+ }
+ activeState = Normal;
+ QApplication::restoreOverrideCursor();
+ setMouseCursor( getStateAtPoint(ev->pos()) );
+}
diff --git a/src-qt5/core/libLumina/RootSubWindow.h b/src-qt5/core/libLumina/RootSubWindow.h
index c56f3c96..fcf0fdae 100644
--- a/src-qt5/core/libLumina/RootSubWindow.h
+++ b/src-qt5/core/libLumina/RootSubWindow.h
@@ -10,41 +10,67 @@
#ifndef _LUMINA_ROOT_WINDOW_SUB_WINDOW_H
#define _LUMINA_ROOT_WINDOW_SUB_WINDOW_H
-#include <QMdiArea>
-#include <QMdiSubWindow>
#include <QWindow>
#include <QWidget>
#include <QCloseEvent>
-
+#include <QFrame>
+#include <QBoxLayout>
+#include <QLabel>
+#include <QToolButton>
+#include <QMenu>
#include <NativeWindow.h>
-class RootSubWindow : public QMdiSubWindow{
+class RootSubWindow : public QFrame{
Q_OBJECT
public:
- RootSubWindow(QMdiArea *root, NativeWindow *win);
+ RootSubWindow(QWidget *root, NativeWindow *win);
~RootSubWindow();
WId id();
private:
+ //Window status
+ enum ModState{Normal, Move, ResizeTop, ResizeTopRight, ResizeRight, ResizeBottomRight, ResizeBottom, ResizeBottomLeft, ResizeLeft, ResizeTopLeft};
+ ModState activeState;
+ 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
+ //Native window embed objects
NativeWindow *WIN;
QWidget *WinWidget;
bool closing;
+ //Title bar objects
+ QBoxLayout *titleBar, *mainLayout;
+ QToolButton *closeB, *maxB, *minB;
+ QLabel *titleLabel;
+ QMenu *otherM; //menu of other actions
+ void initWindowFrame();
void LoadProperties( QList< NativeWindow::Property> list);
public slots:
void clientClosed();
+
+ //Button Actions - public so they can be tied to key shortcuts and stuff as well
+ void toggleMinimize();
+ void toggleMaximize();
+ void triggerClose();
+ void toggleSticky();
+ void activate();
+
+ //Mouse Interactivity
+ void startMoving();
+ void startResizing();
private slots:
- void clientHidden();
- void clientShown();
void aboutToActivate();
void propertyChanged(NativeWindow::Property, QVariant);
-
protected:
- void closeEvent(QCloseEvent*);
+ void mousePressEvent(QMouseEvent*);
+ void mouseMoveEvent(QMouseEvent*);
+ void mouseReleaseEvent(QMouseEvent*);
};
bgstack15