Merge pull request #999 from projectkk2glider/mixes_tab_dragdrop_bug_issue_997

Improvement of inputs and mixers tabs in companion
This commit is contained in:
Bertrand Songis
2014-04-21 13:01:37 +02:00
6 changed files with 235 additions and 76 deletions
+76 -28
View File
@@ -55,6 +55,7 @@ void InputsPanel::update()
// i -> mixer number
QByteArray qba;
ExposlistWidget->clear();
firstLine = true;
int curDest = -1;
for (int i=0; i<C9X_MAX_EXPOS; i++) {
@@ -66,20 +67,86 @@ void InputsPanel::update()
while (curDest<(int)md->chn-1) {
curDest++;
str = getInputStr(model, curDest);
qba.clear();
qba.append((quint8)-curDest-1);
QListWidgetItem *itm = new QListWidgetItem(str);
itm->setData(Qt::UserRole,qba);
ExposlistWidget->addItem(itm);
AddInputLine(-curDest-1);
}
if (AddInputLine(i)) {
curDest++;
}
if (curDest!=(int)md->chn) {
}
while (curDest<inputsCount-1) {
curDest++;
AddInputLine(-curDest-1);
}
lock = false;
}
/**
@brief Creates new input line (list item) and adds it to the list widget
@note Input lines are now HTML formated because they use same widget as mixers.
@param[in] dest defines which input line to create.
If dest < 0 then create empty input slot for input -dest ( dest=-6 -> Input05)
if dest >=0 then create used input based on model input data from slot dest (dest=4 -> model expoData[4])
@retval true created input number is different from the previous list item
false created input number is the same as previous list item
*/
bool InputsPanel::AddInputLine(int dest)
{
bool new_ch;
QString str = getInputText(dest, &new_ch);
QListWidgetItem *itm = new QListWidgetItem(str);
QByteArray qba(1, (quint8)dest);
if (dest >= 0) {
//add input data
ExpoData *md = &model.expoData[dest];
qba.append((const char*)md, sizeof(ExpoData));
}
itm->setData(Qt::UserRole, qba);
#if MIX_ROW_HEIGHT_INCREASE > 0
if (new_ch && !firstLine) {
//increase size of this row
itm->setData(GroupHeaderRole, 1);
}
#endif
ExposlistWidget->addItem(itm);
firstLine = false;
//qDebug() << "InputsPanel::AddInputLine(): dest" << dest << "text" << str;
return new_ch;
}
/**
@brief Returns HTML formated input representation
@param[in] dest defines which input line to create.
If dest < 0 then create empty input slot for input -dest ( dest=-6 -> Input05)
if dest >=0 then create used input based on model input data from slot dest (dest=4 -> model expoData[4])
@retval string input line in HTML
*/
QString InputsPanel::getInputText(int dest, bool * new_ch)
{
QString str;
if (new_ch) *new_ch = 0;
if (dest < 0) {
str = getInputStr(model, -dest-1);
if (new_ch) *new_ch = 1;
}
else {
ExpoData *md = &model.expoData[dest];
if ((dest == 0) || (model.expoData[dest-1].chn != md->chn)) {
if (new_ch) *new_ch = 1;
if (firmware->getCapability(VirtualInputs))
str = QString("%1").arg(getInputStr(model, md->chn), -8, ' ');
else
str = getInputStr(model, md->chn);
curDest = md->chn;
}
else {
if (firmware->getCapability(VirtualInputs))
@@ -117,29 +184,10 @@ void InputsPanel::update()
QString expoName = md->name;
if (!expoName.isEmpty()) str += QString(" [%1]").arg(expoName);
}
qba.clear();
qba.append((quint8)i);
qba.append((const char*)md, sizeof(ExpoData));
QListWidgetItem *itm = new QListWidgetItem(str);
itm->setData(Qt::UserRole,qba); // expo number
ExposlistWidget->addItem(itm); //(str);
}
while (curDest<inputsCount-1) {
curDest++;
QString str = getInputStr(model, curDest);
qba.clear();
qba.append((quint8)-curDest-1);
QListWidgetItem *itm = new QListWidgetItem(str);
itm->setData(Qt::UserRole,qba); // add new expo
ExposlistWidget->addItem(itm);
}
lock = false;
return Qt::escape(str).replace(" ", "&nbsp;");
}
bool InputsPanel::gm_insertExpo(int idx)
{
if (idx<0 || idx>=C9X_MAX_EXPOS || model.expoData[C9X_MAX_EXPOS-1].mode > 0) {
+3
View File
@@ -33,6 +33,7 @@ class InputsPanel : public ModelPanel
private:
bool expoInserted;
MixersList *ExposlistWidget;
bool firstLine;
int getExpoIndex(unsigned int dch);
bool gm_insertExpo(int idx);
@@ -43,6 +44,8 @@ class InputsPanel : public ModelPanel
QList<int> createExpoListFromSelected();
void setSelectedByExpoList(QList<int> list);
void pasteExpoMimeData(const QMimeData * mimeData, int destIdx);
bool AddInputLine(int dest);
QString getInputText(int dest, bool * new_ch);
};
+87 -14
View File
@@ -10,6 +10,7 @@ MixersList::MixersList(QWidget *parent, bool expo) :
setDragEnabled(true);
setAcceptDrops(true);
setDropIndicatorShown(true);
setItemDelegate(new MixersDelegate(parent)); //set custom paint handler
}
void MixersList::keyPressEvent(QKeyEvent *event)
@@ -17,38 +18,110 @@ void MixersList::keyPressEvent(QKeyEvent *event)
emit keyWasPressed(event);
}
/**
@brief Override to give us different mime type for mixers and inputs
*/
QStringList MixersList::mimeTypes () const
{
QStringList types;
if (expo) types << "application/x-companion-expo-item";
else types << "application/x-companion-mix-item";
return types;
}
bool MixersList::dropMimeData( int index, const QMimeData * data, Qt::DropAction action )
{
QByteArray dropData = data->data("application/x-qabstractitemmodeldatalist");
// qDebug() << "MixersList::dropMimeData() index:" << index << "formats" << data->formats();
QByteArray dropData = data->data(expo ? "application/x-companion-expo-item" : "application/x-companion-mix-item");
if (dropData.isNull() ) return false;
QDataStream stream(&dropData, QIODevice::ReadOnly);
QByteArray qba;
while (!stream.atEnd())
{
while (!stream.atEnd()) {
int r,c;
QMap<int, QVariant> v;
stream >> r >> c >> v;
QList<QVariant> lsVars;
lsVars = v.values();
QString itemString = lsVars.at(0).toString();
qba.append(lsVars.at(1).toByteArray().mid(1));
if(itemString.isEmpty()) {};
// qDebug() << "MixersList::dropMimeData() added" << lsVars.count() << "items, data:" << lsVars;
}
if(qba.length()>0)
{
if(qba.length()>0) {
QMimeData *mimeData = new QMimeData;
if (expo)
mimeData->setData("application/x-companion-expo", qba);
else
mimeData->setData("application/x-companion-mix", qba);
mimeData->setData(expo ? "application/x-companion-expo" : "application/x-companion-mix", qba);
emit mimeDropped(index, mimeData, action);
delete mimeData; //is this correct? is mimeData freed elswere??
}
return true;
}
/**
@brief Paints our HTML formated list item text
*/
void MixersDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyleOptionViewItemV4 options = option;
initStyleOption(&options, index);
painter->save();
//setup html document
QTextDocument doc;
SetupDocument(doc, options);
options.text = "";
options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options, painter);
if ( index.model()->data(index, GroupHeaderRole).toInt() > 0 ) {
//paint with added space
painter->translate(options.rect.left(), options.rect.top() + MIX_ROW_HEIGHT_INCREASE);
QRect clip(0, 0, options.rect.width(), options.rect.height() - MIX_ROW_HEIGHT_INCREASE);
doc.drawContents(painter, clip);
}
else {
painter->translate(options.rect.left(), options.rect.top());
QRect clip(0, 0, options.rect.width(), options.rect.height());
doc.drawContents(painter, clip);
}
painter->restore();
}
/**
@brief Returns needed size for our HTML formated list item text
*/
QSize MixersDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
QStyleOptionViewItemV4 options = option;
initStyleOption(&options, index);
//setup html document
QTextDocument doc;
SetupDocument(doc, options);
//qDebug() << "MixersDelegate::sizeHint() UserRole-> " << index.model()->data(index, Qt::UserRole + 2);
int height = doc.size().height();
if ( index.model()->data(index, Qt::UserRole + 2).toInt() > 0 ) {
//qDebug() << "MixersDelegate::sizeHint() detected channel head";
height = doc.size().height() + MIX_ROW_HEIGHT_INCREASE;
}
//qDebug() << "MixersDelegate::sizeHint() options.rect " << options.rect;
//qDebug() << "MixersDelegate::sizeHint() result " << QSize(doc.idealWidth(), height) << options.rect.width();
return QSize(doc.idealWidth(), height);
}
void MixersDelegate::SetupDocument(QTextDocument & doc, const QStyleOptionViewItemV4 & options) const
{
//setup html document
doc.setHtml(options.text);
doc.setDefaultFont(options.font);
//minimize margins (default margins look ugly)
QTextFrame *tf = doc.rootFrame();
QTextFrameFormat tff = tf->frameFormat();
tff.setMargin(0);
tf->setFrameFormat(tff);
}
+26
View File
@@ -3,6 +3,10 @@
#include <QtGui>
#define MIX_ROW_HEIGHT_INCREASE 8 //how much space is added above mixer row (for new channel), if 0 space adding is disabled
const int GroupHeaderRole = (Qt::UserRole+2); //defines new user role for list items. If value is > 0, then space is added before that item
class MixersList : public QListWidget
{
Q_OBJECT
@@ -18,10 +22,32 @@ class MixersList : public QListWidget
public slots:
bool dropMimeData(int index, const QMimeData *data, Qt::DropAction action);
protected:
virtual QStringList mimeTypes() const;
private:
QPoint dragStartPosition;
bool expo;
};
/**
@brief Provides sizing and painting of items for our mixes and inputs lists
This class draws HTML formated strings into QListWidget class
*/
class MixersDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
inline MixersDelegate(QObject *parent) : QStyledItemDelegate(parent) {};
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const;
private:
void SetupDocument(QTextDocument & doc, const QStyleOptionViewItemV4 & options) const;
};
#endif // MIXERSLIST_H
+42 -33
View File
@@ -57,15 +57,16 @@ QString MixesPanel::getChannelLabel(int curDest)
name.append(" ");
str += name.left(8);
}
return str;
return Qt::escape(str);
}
void MixesPanel::update()
{
// curDest -> destination channel4
// curDest -> destination channel
// i -> mixer number
QByteArray qba;
MixerlistWidget->clear();
firstLine = true;
unsigned int curDest = 0;
int i;
unsigned int outputs = firmware->getCapability(Outputs);
@@ -90,50 +91,62 @@ void MixesPanel::update()
}
}
#define MIX_ROW_HEIGHT_INCREASE 8 //how much space is added above mixer row (for new channel), if 0 space adding is disabled
/**
@brief Creates new mixer line (list item) and adds it to the list widget
@note Mixer lines are now HTML formated in order to support bold text.
@param[in] dest defines which mixer line to create.
If dest < 0 then create empty channel slotr fo channel -dest ( dest=-2 -> CH2)
if dest >=0 then create used channel based on model mix data from slot dest (dest=4 -> model mix[4])
@retval true destination channel is different from the previous list item
false destination channle is the same as previous list item
*/
bool MixesPanel::AddMixerLine(int dest)
{
bool new_ch;
QString str = getMixerText(dest, &new_ch);
QListWidgetItem *itm = new QListWidgetItem();
itm->setData(Qt::UserRole, QByteArray(1, (quint8)dest));
QListWidgetItem *itm = new QListWidgetItem(str);
QByteArray qba(1, (quint8)dest);
if (dest >= 0) {
//add mix data
MixData *md = &model.mixData[dest];
qba.append((const char*)md, sizeof(MixData));
}
itm->setData(Qt::UserRole, qba);
#if MIX_ROW_HEIGHT_INCREASE > 0
if ((new_ch && (dest > 0)) || (dest < 0)) {
if (new_ch && !firstLine) {
//increase size of this row
QFontMetrics * fm = new QFontMetrics(itm->font());
QRect rect = fm->boundingRect("C)");
itm->setSizeHint(QSize(-1, (rect.height() * (14+MIX_ROW_HEIGHT_INCREASE))/10));
itm->setData(GroupHeaderRole, 1);
}
#endif
MixerlistWidget->addItem(itm);
MixerlistWidget->setItemWidget(itm, getMixerWidget(str));
// qDebug() << "MixesPanel::AddMixerLine(): " << str;
firstLine = false;
// qDebug() << "MixesPanel::AddMixerLine(): dest" << dest << "text" << str;
return new_ch;
}
QWidget * MixesPanel::getMixerWidget(const QString & mixer_text)
{
QLabel * l = new QLabel();
l->setFont(QFont("Courier New",12));
l->setTextFormat(Qt::RichText);
l->setAlignment(Qt::AlignBottom);
QString formated_str(mixer_text);
formated_str.replace(" ", "&nbsp;");
l->setText(formated_str);
return l;
}
/**
@brief Returns HTML formated mixer representation
@param[in] dest defines which mixer line to create.
If dest < 0 then create empty channel slot for channel -dest ( dest=-2 -> CH2)
if dest >=0 then create used channel based on model mix data from slot dest (dest=4 -> model mix[4])
@retval string mixer line in HTML
*/
QString MixesPanel::getMixerText(int dest, bool * new_ch)
{
QString str;
*new_ch = 0;
if (new_ch) *new_ch = 0;
if (dest < 0) {
str = getChannelLabel(-dest);
//highlight channell if needed
if (-dest == (int)highlightedSource) {
str = "<b>" + str + "</b>";
}
if (new_ch) *new_ch = 1;
}
else {
MixData *md = &model.mixData[dest];
@@ -141,12 +154,12 @@ QString MixesPanel::getMixerText(int dest, bool * new_ch)
str = getChannelLabel(md->destCh);
if ((dest == 0) || (model.mixData[dest-1].destCh != md->destCh)) {
*new_ch = 1;
if (new_ch) *new_ch = 1;
//highlight channell if needed
if (md->destCh == highlightedSource) {
str = "<b>" + str + "</b>";
}
}
}
else {
str.fill(' ');
}
@@ -201,7 +214,7 @@ QString MixesPanel::getMixerText(int dest, bool * new_ch)
}
}
}
return str;
return str.replace(" ", "&nbsp;");
}
bool MixesPanel::gm_insertMix(int idx)
@@ -426,9 +439,7 @@ void MixesPanel::mixerHighlight()
// qDebug() << "MixesPanel::mixerHighlight(): " << highlightedSource ;
for(int i=0; i<MixerlistWidget->count(); i++) {
int t = MixerlistWidget->item(i)->data(Qt::UserRole).toByteArray().at(0);
bool dummy;
QWidget *w = getMixerWidget(getMixerText(t, &dummy));
MixerlistWidget->setItemWidget(MixerlistWidget->item(i), w);
MixerlistWidget->item(i)->setText(getMixerText(t, 0));
}
}
@@ -483,6 +494,7 @@ void MixesPanel::mixerlistWidget_customContextMenuRequested(QPoint pos)
void MixesPanel::mimeMixerDropped(int index, const QMimeData *data, Qt::DropAction /*action*/)
{
int idx= MixerlistWidget->item(index > 0 ? index-1 : 0)->data(Qt::UserRole).toByteArray().at(0);
//qDebug() << "MixesPanel::mimeMixerDropped()" << index << data;
pasteMixerMimeData(data, idx);
}
@@ -510,14 +522,11 @@ void MixesPanel::mixerlistWidget_KeyPress(QKeyEvent *event)
int MixesPanel::gm_moveMix(int idx, bool dir) //true=inc=down false=dec=up
{
if(idx>firmware->getCapability(Mixes) || (idx==firmware->getCapability(Mixes) && dir)) return idx;
if(idx>firmware->getCapability(Mixes) || (idx==0 && !dir) || (idx==firmware->getCapability(Mixes) && dir)) return idx;
int tdx = dir ? idx+1 : idx-1;
MixData &src=model.mixData[idx];
MixData &tgt=model.mixData[tdx];
if (src.destCh == 1 && !dir)
return idx;
unsigned int outputs = firmware->getCapability(Outputs);
if((src.destCh==0) || (src.destCh>outputs) || (tgt.destCh>outputs)) return idx;
+1 -1
View File
@@ -43,6 +43,7 @@ class MixesPanel : public ModelPanel
MixersList *MixerlistWidget;
bool mixInserted;
unsigned int highlightedSource;
bool firstLine;
int getMixerIndex(unsigned int dch);
bool gm_insertMix(int idx);
@@ -55,7 +56,6 @@ class MixesPanel : public ModelPanel
QString getChannelLabel(int curDest);
bool AddMixerLine(int dest);
QString getMixerText(int dest, bool * new_ch);
QWidget * getMixerWidget(const QString & mixer_text);
};
#endif // MIXES_H