Example #1
0
QVariant ChannelModel::data(const QModelIndex& index, int role) const
{
    if (m_currentLayer.isValid() && index.isValid())
    {
        QList<KoChannelInfo*> channels = m_currentLayer->colorSpace()->channels();
        int channelIndex = KoChannelInfo::displayPositionToChannelIndex(index.row(), channels);

        switch (role) {
        case Qt::DisplayRole:
        {
            return channels.at(channelIndex)->name();
        }   
        case Qt::CheckStateRole: {
            Q_ASSERT(index.row() < rowCount());
            Q_ASSERT(index.column() < columnCount());
            
            if (index.column() == 0) {
                QBitArray flags = m_currentLayer->channelFlags();
                return (flags.isEmpty() || flags.testBit(channelIndex)) ? Qt::Checked : Qt::Unchecked;
            }
            
            QBitArray flags = dynamic_cast<const KisPaintLayer*>(m_currentLayer.data())->channelLockFlags();
            return (flags.isEmpty() || flags.testBit(channelIndex)) ? Qt::Unchecked : Qt::Checked;
        }
        }
    }
    return QVariant();
}
Example #2
0
void
VolumeMask::erodeBitmask(int mind, int maxd,
			 int minw, int maxw,
			 int minh, int maxh)
{
//  QProgressDialog progress("Eroding Tag Mask",
//			   "Cancel",
//			   0, 100,
//			   0);

  QBitArray bitcopy = m_bitmask;

  for(int d=mind; d<=maxd; d++)
    {
      emit progressChanged((int)(100.0*(float)d/(float)m_depth));
      qApp->processEvents();

      for(int w=minw; w<=maxw; w++)
	for(int h=minh; h<=maxh; h++)
	  {
	    qint64 bidx = (d*m_width*m_height +
			   w*m_height + h);
	    if (bitcopy.testBit(bidx))
	      {
		int d0 = qMax(d-1, mind);
		int d1 = qMin(d+1, maxd);
		int w0 = qMax(w-1, minw);
		int w1 = qMin(w+1, maxw);
		int h0 = qMax(h-1, minh);
		int h1 = qMin(h+1, maxh);

		bool ok = true;
		for(int d2=d0; d2<=d1; d2++)
		  for(int w2=w0; w2<=w1; w2++)
		    for(int h2=h0; h2<=h1; h2++)
		      {
			qint64 idx = d2*m_width*m_height +
			             w2*m_height + h2;
			ok &= bitcopy.testBit(idx);
		      }

		if (!ok) // surface voxel
		  m_bitmask.setBit(bidx, false); // set bit to 0
	      }
	    
	  }
    }

  emit progressReset();
}
Example #3
0
void
VolumeMask::tagDSlice(int d, QBitArray bitmask, uchar *usermask)
{
  checkMaskFile();

  int nbytes = m_width*m_height;
  uchar *mask = new uchar[nbytes];
  int tag = Global::tag();

  uchar *mslice = m_maskFileManager.getSlice(d);      
  memcpy(mask, mslice, nbytes);

  qint64 idx = 0;
  for(int w=0; w<m_width; w++)
    for(int h=0; h<m_height; h++)
      {
	qint64 midx = d*m_width*m_height + w*m_height + h;
	if (bitmask.testBit(midx))
	  {
	    if (usermask[4*idx] > 0)
	      mask[idx] = tag;
	  }
	idx ++;
      }
  
  m_maskFileManager.setSlice(d, mask);
  delete [] mask;
}
Example #4
0
void Recurrence::addMonthlyPos( short pos, const QBitArray &days )
{
  // Allow 53 for yearly!
  if ( d->mRecurReadOnly || pos > 53 || pos < -53 ) {
    return;
  }

  RecurrenceRule *rrule = defaultRRule( false );
  if ( !rrule ) {
    return;
  }
  bool changed = false;
  QList<RecurrenceRule::WDayPos> positions = rrule->byDays();

  for ( int i = 0; i < 7; ++i ) {
    if ( days.testBit( i ) ) {
      RecurrenceRule::WDayPos p( pos, i + 1 );
      if ( !positions.contains( p ) ) {
        changed = true;
        positions.append( p );
      }
    }
  }
  if ( changed ) {
    rrule->setByDays( positions );
    updated();
  }
}
Example #5
0
void
TrisetObject::paint(QGLViewer *viewer,
		    QBitArray doodleMask,
		    float *depthMap,
		    Vec tcolor, float tmix)
{
  int swd = viewer->camera()->screenWidth();
  int sht = viewer->camera()->screenHeight();

  for(int i=0; i<m_tvertices.count(); i++)
    {
      Vec scr = viewer->camera()->projectedCoordinatesOf(m_tvertices[i]);
      int tx = scr.x;
      int ty = sht-scr.y;
      float td = scr.z;
      if (tx>0 && tx<swd && ty>0 && ty<sht)
	{
	  int idx = ty*swd + tx;
	  if (doodleMask.testBit(idx))
	    {
	      float zd = depthMap[idx];
	      if (fabs(zd-td) < 0.0002)
		m_vcolor[i] = tmix*tcolor + (1.0-tmix)*m_vcolor[i];
	    }
	}
    }
}
Example #6
0
QList<QWidget *> FatherBlock::GetEnableBlocksWidget(int theStatusIndex)
{
    QList<QWidget *>theBlockWidgets;
    if(theStatusIndex == -1)
    {
        theStatusIndex = m_current_status_index;
    }
    if(theStatusIndex < m_status_list.count())
    {
        QBitArray theStatus = m_status_list[theStatusIndex];
        int count = theStatus.count()-1;
        while(count >= 0)
        {
            if(theStatus.testBit(count) == true)
            {
                QWidget *ChildBlockWidget = GetSingleBlock(m_block_type);
                ChildBlockWidget->setStyleSheet(m_BlockStyleSheet);
                ChildBlockWidget->setGeometry(m_blocks_list[count]->geometry());
                ChildBlockWidget->setGeometry(ChildBlockWidget->x()+this->x(),ChildBlockWidget->y()+this->y(),ChildBlockWidget->width(),ChildBlockWidget->height());
                theBlockWidgets.append(ChildBlockWidget);
            }
            count--;
        }
    }
    return theBlockWidgets;
}
    /**
     * Spread contacts in the blockmap to any touched neighbors.
     *
     * @param box   Map space region in which to perform spreading.
     */
    void spread(AABoxd const &box)
    {
        BlockmapCellBlock const cellBlock = _blockmap.toCellBlock(box);

        BlockmapCell cell;
        for(cell.y = cellBlock.min.y; cell.y < cellBlock.max.y; ++cell.y)
        for(cell.x = cellBlock.min.x; cell.x < cellBlock.max.x; ++cell.x)
        {
            if(_spreadBlocks)
            {
                // Should we skip this cell?
                int cellIndex = _blockmap.toCellIndex(cell.x, cell.y);
                if(_spreadBlocks->testBit(cellIndex))
                    continue;

                // Mark the cell as processed.
                _spreadBlocks->setBit(cellIndex);
            }

            _blockmap.forAllInCell(cell, [this] (void *element)
            {
                spreadContact(*static_cast<Contact *>(element));
                return LoopContinue;
            });
        }
    }
// Sends the complete list of pieces that we have downloaded.
void PeerWireClient::sendPieceList(const QBitArray &bitField)
{
    // The bitfield message may only be sent immediately after the
    // handshaking sequence is completed, and before any other
    // messages are sent.
    if (!sentHandShake)
        sendHandShake();

    // Don't send the bitfield if it's all zeros.
    if (bitField.count(true) == 0)
	return;

    int bitFieldSize = bitField.size();
    int size = (bitFieldSize + 7) / 8;
    QByteArray bits(size, '\0');
    for (int i = 0; i < bitFieldSize; ++i) {
        if (bitField.testBit(i)) {
            quint32 byte = quint32(i) / 8;
            quint32 bit = quint32(i) % 8;
            bits[byte] = uchar(bits.at(byte)) | (1 << (7 - bit));
        }
    }

    char message[] = {0, 0, 0, 1, 5};
    toNetworkData(bits.size() + 1, &message[0]);
    write(message, sizeof(message));
    write(bits);
}
Example #9
0
void
VolumeMask::tagHSlice(int h, QBitArray bitmask, uchar *usermask)
{
  checkMaskFile();

  int nbytes = m_width*m_height;
  uchar *mask = new uchar[nbytes];
  int tag = Global::tag();
  qint64 bidx = 0;

  for(int d=0; d<m_depth; d++)
    {
      uchar *mslice = m_maskFileManager.getSlice(d);      
      memcpy(mask, mslice, nbytes);
      for(int w=0; w<m_width; w++)
	{
	  qint64 midx = d*m_width*m_height + w*m_height + h;
	  if (bitmask.testBit(midx))
	    {
	      qint64 bidx = (d*m_width + w);
	      qint64 idx = (w*m_height + h);
	      if (usermask[4*bidx] > 0)
		mask[idx] = tag;
	    }
	}
  
      m_maskFileManager.setSlice(d, mask);
    }

  delete [] mask;
}
/******************************************************************************
* Replaces the particle selection.
******************************************************************************/
void ParticleSelectionSet::setParticleSelection(const PipelineFlowState& state, const QBitArray& selection, SelectionMode mode)
{
	// Make a backup of the old snapshot so it may be restored.
	if(dataset()->undoStack().isRecording())
		dataset()->undoStack().push(new ReplaceSelectionOperation(this));

	ParticlePropertyObject* identifierProperty = ParticlePropertyObject::findInState(state, ParticleProperty::IdentifierProperty);
	if(identifierProperty && useIdentifiers()) {
		OVITO_ASSERT(selection.size() == identifierProperty->size());
		_selection.clear();
		int index = 0;
		if(mode == SelectionReplace) {
			_selectedIdentifiers.clear();
			for(int id : identifierProperty->constIntRange()) {
				if(selection.testBit(index++))
					_selectedIdentifiers.insert(id);
			}
		}
		else if(mode == SelectionAdd) {
			for(int id : identifierProperty->constIntRange()) {
				if(selection.testBit(index++))
					_selectedIdentifiers.insert(id);
			}
		}
		else if(mode == SelectionSubtract) {
			for(int id : identifierProperty->constIntRange()) {
				if(selection.testBit(index++))
					_selectedIdentifiers.remove(id);
			}
		}
	}
	else {
		_selectedIdentifiers.clear();
		if(mode == SelectionReplace)
			_selection = selection;
		else if(mode == SelectionAdd) {
			_selection.resize(selection.size());
			_selection |= selection;
		}
		else if(mode == SelectionSubtract) {
			_selection.resize(selection.size());
			_selection &= ~selection;
		}
	}

	notifyDependents(ReferenceEvent::TargetChanged);
}
Example #11
0
void
VolumeMask::erode(int mind, int maxd,
		  int minw, int maxw,
		  int minh, int maxh,
		  QBitArray vbitmask)
{
  createBitmask();

  //int thickness = Global::spread();
  int thickness = 1;
  while (thickness > 0)
    {
      erodeBitmask(mind, maxd,
		   minw, maxw,
		   minh, maxh);
      thickness --;
    }

  // m_bitmask now contains region eroded by thickness

//  QProgressDialog progress("Updating Mask",
//			   "Cancel",
//			   0, 100,
//			   0);

  int nbytes = m_width*m_height;
  unsigned char *mask = new unsigned char[nbytes];

  for(int d=mind; d<=maxd; d++)
    { 
      emit progressChanged((int)(100.0*(float)d/(float)m_depth));
      qApp->processEvents();
      
      uchar *mslice = m_maskFileManager.getSlice(d);      
      memcpy(mask, mslice, nbytes);

      for(int w=minw; w<=maxw; w++)
	for(int h=minh; h<=maxh; h++)
	  {
	    qint64 bidx = (d*m_width*m_height +
			w*m_height + h);	    
	    if (  vbitmask.testBit(bidx) &&
		!m_bitmask.testBit(bidx))
	      {
		// reset mask to 0 if the
		// mask value is same as supplied tag value
		qint64 idx = (w*m_height + h);
		if ( mask[idx] == Global::tag())
		  mask[idx] = 0;
	      }
	  }

      m_maskFileManager.setSlice(d, mask);
    }

  delete [] mask;

  emit progressReset();
}
QRect ImageOverlayRegionFinder::growRegion(int row, int column, QBitArray &mask)
{
    QRect region;
    region.setCoords(column, row, column, row);

    QQueue<int> queue;
    queue.enqueue(getDataIndex(row, column));

    while (!queue.isEmpty())
    {
        int i = queue.dequeue();

        if (m_overlay.getData()[i] > 0 && !mask.testBit(i))
        {
            mask.setBit(i);
            row = getRowIndex(i);
            column = getColumnIndex(i);
            
            if (row < region.top())
            {
                region.setTop(row);
            }
            if (row > region.bottom())
            {
                region.setBottom(row);
            }
            if (column < region.left())
            {
                region.setLeft(column);
            }
            if (column > region.right())
            {
                region.setRight(column);
            }

            if (column - 1 >= 0)
            {
                queue.enqueue(getDataIndex(row, column - 1));
            }
            if (column + 1 < static_cast<signed>(m_overlay.getColumns()))
            {
                queue.enqueue(getDataIndex(row, column + 1));
            }
            if (row - 1 >= 0)
            {
                queue.enqueue(getDataIndex(row - 1, column));
            }
            if (row + 1 < static_cast<signed>(m_overlay.getRows()))
            {
                queue.enqueue(getDataIndex(row + 1, column));
            }
        }
    }

    return region;
}
Example #13
0
bool KoList::continueNumbering(int level) const
{
    Q_ASSERT(level > 0 && level <= 10);
    level = qMax(qMin(level, 10), 1);

    QBitArray bitArray = d->properties.value(ContinueNumbering).toBitArray();
    if (bitArray.isEmpty())
        return false;
    return bitArray.testBit(level-1);
}
Example #14
0
void KisChannelFlagsWidget::setChannelFlags(const QBitArray & cf)
{
    dbgUI << "KisChannelFlagsWidget::setChannelFlags " << cf.isEmpty();
    if (cf.isEmpty()) return;

    QBitArray channelFlags = m_colorSpace->setChannelFlagsToColorSpaceOrder(cf);
    for (int i = 0; i < qMin(m_channelChecks.size(), channelFlags.size()); ++i) {
        m_channelChecks.at(i)->setChecked(channelFlags.testBit(i));
    }
}
T typeFromBitArray(QBitArray &array) {
    Q_ASSERT(sizeof(T) <= sizeof(quint64));
    quint64 mask = 0x0000000000000001;
    T resultVector(0);
    for (uint i = 0; i < 8 * sizeof (T); ++i) {
        if (array.testBit(i))
            resultVector |= mask;
        mask <<= 1;
    }
    return resultVector;
}
Example #16
0
void QLCDNumber::setNumDigits( int numDigits )
{
    if ( numDigits > 99 ) {
#if defined(QT_CHECK_RANGE)
        qWarning( "QLCDNumber::setNumDigits: (%s) Max 99 digits allowed",
                 name( "unnamed" ) );
#endif
        numDigits = 99;
    }
    if (numDigits < 0 ) {
#if defined(QT_CHECK_RANGE)
        qWarning( "QLCDNumber::setNumDigits: (%s) Min 0 digits allowed",
                 name( "unnamed" ) );
#endif
        numDigits = 0;
    }
    if ( digitStr.isNull() ) {                  // from constructor
        ndigits = numDigits;
        digitStr.fill( ' ', ndigits );
        points.fill( 0, ndigits );
        digitStr[ndigits - 1] = '0';            // "0" is the default number
    } else {
        bool doDisplay = ndigits == 0;
        if ( numDigits == ndigits )             // no change
            return;
        register int i;
        int dif;
        if ( numDigits > ndigits ) {            // expand
            dif = numDigits - ndigits;
            QString buf;
            buf.fill( ' ', dif );
            digitStr.insert( 0, buf );
            points.resize( numDigits );
            for ( i=numDigits-1; i>=dif; i-- )
                points.setBit( i, points.testBit(i-dif) );
            for ( i=0; i<dif; i++ )
                points.clearBit( i );
        } else {                                        // shrink
            dif = ndigits - numDigits;
            digitStr = digitStr.right( numDigits );
            QBitArray tmpPoints = points.copy();
            points.resize( numDigits );
            for ( i=0; i<(int)numDigits; i++ )
                points.setBit( i, tmpPoints.testBit(i+dif) );
        }
        ndigits = numDigits;
        if ( doDisplay )
            display( value() );
        update();
    }
}
Example #17
0
void
VolumeMask::dilate(QBitArray vbitmask)
{
  createBitmask();

  //int thickness = Global::spread();
  int thickness = 1;
  while (thickness > 0)
    {
      dilateBitmask();
      thickness --;
    }

  // m_bitmask now contains region dilated by thickness

//  QProgressDialog progress("Updating Mask",
//			   "Cancel",
//			   0, 100,
//			   0);

  int nbytes = m_width*m_height;
  unsigned char *mask = new unsigned char[nbytes];

  qint64 bidx = 0;
  for(int d=0; d<m_depth; d++)
    { 
      emit progressChanged((int)(100.0*(float)d/(float)m_depth));
      qApp->processEvents();
      
      uchar *mslice = m_maskFileManager.getSlice(d);      
      memcpy(mask, mslice, nbytes);

      for(int w=0; w<m_width; w++)
	for(int h=0; h<m_height; h++)
	  {
	    if ( vbitmask.testBit(bidx) &&
		m_bitmask.testBit(bidx))
	      {
		qint64 idx = (w*m_height + h);
		mask[idx] = Global::tag();
	      }
	    bidx++;
	  }
 
      m_maskFileManager.setSlice(d, mask);
    }

  delete [] mask;

  emit progressReset();
}
Example #18
0
/*!
  Sets the current number of digits to \a numDigits. Must
  be in the range 0..99.
 */
void QLCDNumber::setDigitCount(int numDigits)
{
    Q_D(QLCDNumber);
    if (numDigits > 99) {
        qWarning("QLCDNumber::setNumDigits: (%s) Max 99 digits allowed",
                 objectName().toLocal8Bit().constData());
        numDigits = 99;
    }
    if (numDigits < 0) {
        qWarning("QLCDNumber::setNumDigits: (%s) Min 0 digits allowed",
                 objectName().toLocal8Bit().constData());
        numDigits = 0;
    }
    if (d->digitStr.isNull()) {                  // from constructor
        d->ndigits = numDigits;
        d->digitStr.fill(QLatin1Char(' '), d->ndigits);
        d->points.fill(0, d->ndigits);
        d->digitStr[d->ndigits - 1] = QLatin1Char('0'); // "0" is the default number
    } else {
        bool doDisplay = d->ndigits == 0;
        if (numDigits == d->ndigits)             // no change
            return;
        int i;
        int dif;
        if (numDigits > d->ndigits) {            // expand
            dif = numDigits - d->ndigits;
            QString buf;
            buf.fill(QLatin1Char(' '), dif);
            d->digitStr.insert(0, buf);
            d->points.resize(numDigits);
            for (i=numDigits-1; i>=dif; i--)
                d->points.setBit(i, d->points.testBit(i-dif));
            for (i=0; i<dif; i++)
                d->points.clearBit(i);
        } else {                                        // shrink
            dif = d->ndigits - numDigits;
            d->digitStr = d->digitStr.right(numDigits);
            QBitArray tmpPoints = d->points;
            d->points.resize(numDigits);
            for (i=0; i<(int)numDigits; i++)
                d->points.setBit(i, tmpPoints.testBit(i+dif));
        }
        d->ndigits = numDigits;
        if (doDisplay)
            display(value());
        update();
    }
}
Example #19
0
err_info *Pagemodel::commit (void)
   {
   Desktopmodel *contents = (Desktopmodel *)_contents;
   QModelIndex index = _stackindex;   // may be invalid
   int del_count = 0;
   QVector<Pageinfo> *pages = &_pages;
   bool lost = _lost_scan;

   if (lost)
      {
      pages = &_scan_pages;
      _lost_scan = false;
      contents = (Desktopmodel *)_lost_contents;
      _lost_contents = 0;
      }
   if (!contents)
      return NULL;

   // delete any pages marked for deletion
   QBitArray ba (pages->size ());

   for (int i = 0; i < pages->size (); i++)
      if ((*pages) [i].toRemove ())
         {
         ba.setBit (i);
         del_count++;
         }

   // process on our local model (reverse order)
   if (!lost) for (int i = pages->size () - 1; i >= 0; i--)
      if (ba.testBit (i))
         removeRow (i, QModelIndex ());

   // update any annotation data
   if (!lost && index.isValid ())
      contents->updateAnnot (index, _annot_updates);

   //FIXME: need to write ocr text somewhere also, but needs to be page-based
   //FIXME: should only update annotations if they have changed
   //FIXME: what happens if they delete all pages? Should delete the stack

   /* now delete the pages we don't want, or trash the whole stack if
      we want none of them. This function also handles the case where
      contents points to another directory */
   // this may invalidate _stackIndex
   // also this function copes with an invalid index
   return contents->scanCommitPages (index, del_count, ba, !lost);
   }
Example #20
0
void
VolumeMask::tagUsingBitmask(QList<int> pos,
			    QBitArray bitmask)
{
  checkMaskFile();

  if (pos.count())
    findConnectedRegion(pos);

//  QProgressDialog progress("Updating Mask",
//			   "Cancel",
//			   0, 100,
//			   0);

  int nbytes = m_width*m_height;
  uchar *mask = new uchar[nbytes];
  int tag = Global::tag();

  qint64 bidx = 0;
  for(int d=0; d<m_depth; d++)
    {
      emit progressChanged((int)(100.0*(float)d/(float)m_depth));
      qApp->processEvents();
      
      uchar *mslice = m_maskFileManager.getSlice(d);      
      memcpy(mask, mslice, nbytes);

      for(int w=0; w<m_width; w++)
	for(int h=0; h<m_height; h++)
	  {
	    if (bitmask.testBit(bidx))
	      {
		qint64 idx = (w*m_height + h);
		//if (tag == 0 || mask[idx] == 0)
		mask[idx] = tag;
	      }

	    bidx++;
	  }

      m_maskFileManager.setSlice(d, mask);
    }
  
  delete [] mask;

  emit progressReset();
}
Example #21
0
void EventWinRecurrence::setCheckedDays(QBitArray &rDays) {
    if (rDays.testBit(0))
        mondayBox->setChecked(TRUE);
    if (rDays.testBit(1))
        tuesdayBox->setChecked(TRUE);
    if (rDays.testBit(2))
        wednesdayBox->setChecked(TRUE);
    if (rDays.testBit(3))
        thursdayBox->setChecked(TRUE);
    if (rDays.testBit(4))
        fridayBox->setChecked(TRUE);
    if (rDays.testBit(5))
        saturdayBox->setChecked(TRUE);
    if (rDays.testBit(6))
        sundayBox->setChecked(TRUE);
}
Example #22
0
void TreeWidget::restoreState(const QByteArray& data)
{
    QVariantMap state;
    QDataStream in(data);
    in >> state;

    if (state.contains("expanded")) {
        QBitArray expanded = state.value("expanded").toBitArray();
        if (expanded.count() == topLevelItemCount()) {
            for (int i = 0; i < expanded.count(); ++i)
                topLevelItem(i)->setExpanded(expanded.testBit(i));
        }
    }
    if (state.contains("sorting")) {
        d.sorting = state.value("sorting").toMap();
        restoreSortOrder();
    }
}
Example #23
0
void
VolumeMask::dilateBitmask()
{
//  QProgressDialog progress("Dilating Tag Mask",
//			   "Cancel",
//			   0, 100,
//			   0);

  QBitArray bitcopy = m_bitmask;
  m_bitmask.fill(false);

  qint64 bidx = 0;
  for(int d=0; d<m_depth; d++)
    {
      emit progressChanged((int)(100.0*(float)d/(float)m_depth));
      qApp->processEvents();

      for(int w=0; w<m_width; w++)
	for(int h=0; h<m_height; h++)
	  {
	    if (bitcopy.testBit(bidx))
	      {
		int d0 = qMax(d-1, 0);
		int d1 = qMin(d+1, m_depth-1);
		int w0 = qMax(w-1, 0);
		int w1 = qMin(w+1, m_width-1);
		int h0 = qMax(h-1, 0);
		int h1 = qMin(h+1, m_height-1);

		for(int d2=d0; d2<=d1; d2++)
		  for(int w2=w0; w2<=w1; w2++)
		    for(int h2=h0; h2<=h1; h2++)
		      {
			qint64 idx = d2*m_width*m_height +
			             w2*m_height + h2;
			m_bitmask.setBit(idx);
		      }
	      }
	    bidx ++;	   
	  }
    }

  emit progressReset();
}
Example #24
0
QList<QRect> FatherBlock::GetEnableBlockRects(int theStatusIndex,bool theRealBlocksFlag)
{
    QList<QRect>theBlockRects;
    if(theStatusIndex == -1)
    {
        theStatusIndex = m_current_status_index;
    }
    if(theStatusIndex < m_status_list.count())
    {
        QBitArray theStatus = m_status_list[theStatusIndex];
        int count = theStatus.count()-1;
        while(count >= 0)
        {
            if(theStatus.testBit(count) == true)
            {
                QRect ChildBlockRect =  QRect(m_blocks_list[count]->geometry());
                ChildBlockRect.setX(ChildBlockRect.x() + this->x());
               ChildBlockRect.setY(ChildBlockRect.y() + this->y());
               ChildBlockRect.setWidth(m_blocks_list[count]->width());
               ChildBlockRect.setHeight(m_blocks_list[count]->height());
                if(!hasBottomBlock(count) && !theRealBlocksFlag)
                {
                    QRect tempBlock(ChildBlockRect);
                    tempBlock.setY(ChildBlockRect.y()+m_blocks_list[count]->height());
                    theBlockRects.append(tempBlock);
                }
                if(!hasRightBlock(count) && !theRealBlocksFlag)
                {
                    QRect tempBlock(ChildBlockRect);
                    tempBlock.setX(ChildBlockRect.x() + m_blocks_list[count]->width());
                    theBlockRects.append(tempBlock);
                }
                 theBlockRects.append(ChildBlockRect);
            }
            count--;
        }
    }
    return theBlockRects;
}
Example #25
0
bool FatherBlock::RotateShape(int theStatusIndex)
{
    if(theStatusIndex < m_status_list.count())
    {
        QBitArray theStatus = m_status_list[theStatusIndex];
        int count = theStatus.count()-1;
        while(count >= 0)
        {
            if(theStatus.testBit(count) == true)
            {
                SetStatusEnable(m_blocks_list[count]);
            }else
            {
                SetStatusDisable(m_blocks_list[count]);
            }
            count--;
        }
        return true;
    }else
    {
        return false;
    }
}
Example #26
0
QBitArray KisChannelFlagsWidget::channelFlags() const
{
    bool allTrue = true;
    QBitArray ba(m_channelChecks.size());

    for (int i = 0; i < m_channelChecks.size(); ++i) {
        
        bool flag = m_channelChecks.at(i)->isChecked();
        if (!flag) allTrue = false;
        
        ba.setBit(i, flag);
        dbgUI << " channel " << i << " is " << flag << ", allTrue = " << allTrue << ", so ba.testBit("<<i<<")" << " is " << ba.testBit(i);
    }
    if (allTrue)
        return QBitArray();
    else {
        QBitArray result = m_colorSpace->setChannelFlagsToPixelOrder(ba);
        for (int i = 0; i < result.size(); ++i) {
            dbgUI << "On conversion to the pixel order, flag " << i << " is " << result.testBit(i);
        }
        return result;
    }
}
Example #27
0
void KeyWidget::paintEvent(QPaintEvent*){
    const QColor bgColor(68, 64, 64);
    const QColor keyColor(112, 110, 110);
    const QColor highlightColor(136, 176, 240);
    const QColor highlightAnimColor(136, 200, 240);
    const QColor animColor(112, 200, 110);

    uint count = keyMap.count();

    // Determine which keys to highlight
    QBitArray highlight;
    switch(mouseDownMode){
    case SET:
        highlight = newSelection;
        break;
    case ADD:
        highlight = selection | newSelection;
        break;
    case SUBTRACT:
        highlight = selection & ~newSelection;
        break;
    case TOGGLE:
        highlight = selection ^ newSelection;
        break;
    default:
        highlight = selection;
    }

    QPainter painter(this);
#if QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)
    int ratio = painter.device()->devicePixelRatio();
#else
    int ratio = 1;
#endif
    float xScale = (float)width() / (keyMap.width() + KEY_SIZE) * ratio;
    float yScale = (float)height() / (keyMap.height() + KEY_SIZE) * ratio;
    // Draw background
    painter.setPen(Qt::NoPen);
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.setBrush(QBrush(bgColor));
    painter.drawRect(0, 0, width(), height());

    // Draw mouse highlight (if any)
    if(mouseDownMode != NONE && (mouseDownX != mouseCurrentX || mouseDownY != mouseCurrentY)){
        int x1 = (mouseDownX > mouseCurrentX) ? mouseCurrentX : mouseDownX;
        int x2 = (mouseDownX > mouseCurrentX) ? mouseDownX : mouseCurrentX;
        int y1 = (mouseDownY > mouseCurrentY) ? mouseCurrentY : mouseDownY;
        int y2 = (mouseDownY > mouseCurrentY) ? mouseDownY : mouseCurrentY;
        painter.setPen(QPen(highlightColor, 0.5));
        QColor bColor = highlightColor;
        bColor.setAlpha(128);
        painter.setBrush(QBrush(bColor));
        painter.drawRect(x1, y1, x2 - x1, y2 - y1);
    }

    // Draw key backgrounds on a separate pixmap so that a drop shadow can be applied to them.
    int wWidth = width(), wHeight = height();
    KeyMap::Model model = keyMap.model();
    QPixmap keyBG(wWidth * ratio, wHeight * ratio);
    keyBG.fill(QColor(0, 0, 0, 0));
    QPainter bgPainter(&keyBG);
    bgPainter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
    bgPainter.setPen(Qt::NoPen);
    for(uint i = 0; i < count; i++){
        const KeyPos& key = *keyMap.key(i);
        float x = key.x + 6.f - key.width / 2.f + 1.f;
        float y = key.y + 6.f - key.height / 2.f + 1.f;
        float w = key.width - 2.f;
        float h = key.height - 2.f;
        // In RGB mode, ignore volume wheel on K70/K95
        if(model != KeyMap::K65 && _rgbMode && (!strcmp(key.name, "volup") || !strcmp(key.name, "voldn")))
            continue;
        // Set color based on key highlight
        if(highlight.testBit(i)){
            if(animation.testBit(i))
                bgPainter.setBrush(QBrush(highlightAnimColor));
            else
                bgPainter.setBrush(QBrush(highlightColor));
        } else if(animation.testBit(i))
            bgPainter.setBrush(QBrush(animColor));
        else
            bgPainter.setBrush(QBrush(keyColor));
        if(!strcmp(key.name, "mr") || !strcmp(key.name, "m1") || !strcmp(key.name, "m2") || !strcmp(key.name, "m3")
                || !strcmp(key.name, "light") || !strcmp(key.name, "lock") || (model == KeyMap::K65 && !strcmp(key.name, "mute"))){
            // Switch keys are circular
            x += w / 8.f;
            y += h / 8.f;
            w *= 0.75f;
            h *= 0.75f;
            bgPainter.drawEllipse(QRectF(x * xScale, y * yScale, w * xScale, h * yScale));
        } else {
            if(!strcmp(key.name, "enter")){
                if(key.height == 24){
                    // ISO enter key isn't rectangular
                    y = key.y + 1.f;
                    h = 10.f;
                    bgPainter.drawRect(QRectF((x + w - 13.f) * xScale, y * yScale, 13.f * xScale, 22.f * yScale));
                } else {
                    // US enter key isn't perfectly centered, needs an extra pixel on the left to appear correctly
                    x -= 1.f;
                    w += 1.f;
                }
            } else if(!strcmp(key.name, "rshift") || !strcmp(key.name, "stop")){
                // A few other keys also need extra pixels
                x -= 1.f;
                w += 1.f;
            } else if(!strcmp(key.name, "caps") || !strcmp(key.name, "lshift") || !strcmp(key.name, "next")){
                w += 1.f;
            }
            bgPainter.drawRect(QRectF(x * xScale, y * yScale, w * xScale, h * yScale));
        }
    }

    // Render the key decorations (RGB -> light circles, binding -> key names) on yet another layer
    QPixmap decoration(wWidth * ratio, wHeight * ratio);
    decoration.fill(QColor(0, 0, 0, 0));
    QPainter decPainter(&decoration);
    decPainter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
    if(_rgbMode){
        // Draw key colors (RGB mode)
        decPainter.setPen(QPen(QColor(255, 255, 255), 1.5));
        for(uint i = 0; i < count; i++){
            const KeyPos& key = *keyMap.key(i);
            if(model != KeyMap::K65 && _rgbMode && (!strcmp(key.name, "volup") || !strcmp(key.name, "voldn")))
                continue;
            float x = key.x + 6.f - 1.8f;
            float y = key.y + 6.f - 1.8f;
            float w = 3.6f;
            float h = 3.6f;
            decPainter.setBrush(QBrush(_colorMap[key.name]));
            decPainter.drawEllipse(QRectF(x * xScale, y * yScale, w * xScale, h * yScale));
        }
    } else {
        // Draw key names
        decPainter.setBrush(Qt::NoBrush);
        QFont font = painter.font();
        font.setBold(true);
        font.setPixelSize(5.25f * yScale);
        QFont font0 = font;
        for(uint i = 0; i < count; i++){
            const KeyPos& key = *keyMap.key(i);
            float x = key.x + 6.f - key.width / 2.f + 1.f;
            float y = key.y + 6.f - key.height / 2.f;
            float w = key.width - 2.f;
            float h = key.height;
            // Print the key's friendly name (with some exceptions)
            QString keyName = KbBind::globalRemap(key.name);
            QString name = key.friendlyName(false);
            name = name.split(" ").last();
            struct _names {
                const char* keyName, *displayName;
            };
            _names names[] = {
                {"light", "☼"}, {"lock", "☒"}, {"mute", "◖⊘"}, {"volup", keyMap.model() == KeyMap::K65 ? "◖))" : "▲"}, {"voldn", keyMap.model() == KeyMap::K65 ? "◖)" : "▼"},
                {"prtscn",  "PrtScn\nSysRq"}, {"scroll", "Scroll\nLock"}, {"pause", "Pause\nBreak"}, {"stop", "▪"}, {"prev", "|◂◂"}, {"play", "▸||"}, {"next", "▸▸|"},
                {"pgup", "Page\nUp"}, {"pgdn", "Page\nDown"}, {"numlock", "Num\nLock"},
                {"caps", "Caps"}, {"lshift", "Shift"}, {"rshift", "Shift"},
#ifdef Q_OS_MACX
                {"lctrl", "⌃"}, {"rctrl", "⌃"}, {"lwin", "⌘"}, {"rwin", "⌘"}, {"lalt", "⌥"}, {"ralt", "⌥"},
#else
                {"lctrl", "Ctrl"}, {"rctrl", "Ctrl"}, {"lwin", "❖"}, {"rwin", "❖"}, {"lalt", "Alt"}, {"ralt", "Alt"},
#endif
                {"rmenu", "▤"}, {"up", "▲"}, {"left", "◀"}, {"down", "▼"}, {"right", "▶"}
            };
            for(uint k = 0; k < sizeof(names) / sizeof(_names); k++){
                if(keyName == names[k].keyName){
                    name = names[k].displayName;
                    break;
                }
            }
            if(keyName == "mr" || keyName == "m1" || keyName == "m2" || keyName == "m3" || keyName == "up" || keyName == "down" || keyName == "left" || keyName == "right")
                // Use a smaller size for MR, M1 - M3, and arrow keys
                font.setPixelSize(font.pixelSize() * 0.75);
            else if(keyName == "end")
                // Use a smaller size for "End" to match everything else in that area
                font.setPixelSize(font.pixelSize() * 0.65);
            else if(keyName == "light"
#ifndef Q_OS_MACX
                    || keyName == "lwin" || keyName == "rwin"
#endif
                    )
                // Use a larger font size for Win and Brightness to compensate for the unicode symbols looking smaller (Linux only)
                font.setPixelSize(font.pixelSize() * 1.3);
            // Determine the appropriate size to draw the text at
            decPainter.setFont(font);
            QRectF rect(x * xScale, y * yScale - 1, w * xScale, h * yScale);
            int flags = Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextWordWrap;
            QRectF bounds = decPainter.boundingRect(rect, flags, name);
            while((bounds.height() >= rect.height() - 8. || bounds.width() >= rect.width() - 2.) && font.pixelSize() >= 5){
                // Scale font size down until it fits inside the key
                font.setPixelSize(font.pixelSize() - 2);
                decPainter.setFont(font);
                bounds = decPainter.boundingRect(rect, flags, name);
            }
            // Pick color based on key function
            QString bind = _bindMap.value(key.name);
            QString def = KbBind::defaultAction(key.name);
            if(bind.isEmpty())
                // Unbound - red
                decPainter.setPen(QColor(255, 136, 136));
            else if(KbBind::isProgram(bind))
                // Custom program - orange
                decPainter.setPen(QColor(255, 224, 192));
            else if(KbBind::isSpecial(bind) && (bind == def || !KbBind::isSpecial(def)))
                // Special function - blue (only if not mapped to a different function - if a special function is remapped, color it yellow)
                decPainter.setPen(QColor(128, 224, 255));
            else if(KbBind::isMedia(bind) && (bind == def || !KbBind::isMedia(def)))
                // Media key - green
                decPainter.setPen(QColor(160, 255, 168));
            else if(bind == def)
                // Standard key - white
                decPainter.setPen(QColor(255, 255, 255));
            else
                // Remapped key - yellow
                decPainter.setPen(QColor(255, 248, 128));
            decPainter.drawText(rect, flags, name);
            font = font0;
        }
    }
    // Create drop shadow effects
    QGraphicsDropShadowEffect* bgEffect = new QGraphicsDropShadowEffect;  // Have to use "new", creating these on the stack causes a crash...
    bgEffect->setBlurRadius(2.);
    bgEffect->setColor(QColor(0, 0, 0, 32));
    bgEffect->setOffset(0, 1);
    QGraphicsDropShadowEffect* decEffect = new QGraphicsDropShadowEffect;
    decEffect->setBlurRadius(4.);
    decEffect->setColor(QColor(0, 0, 0, 104));
    decEffect->setOffset(0, 1);
    // Apply them to the pixmaps
    QGraphicsPixmapItem* bgItem = new QGraphicsPixmapItem(keyBG);
    bgItem->setGraphicsEffect(bgEffect);
    QGraphicsPixmapItem* decItem = new QGraphicsPixmapItem(decoration);
    decItem->setGraphicsEffect(decEffect);
    // Render everything
    QGraphicsScene* scene = new QGraphicsScene;
    scene->addItem(bgItem);
    scene->addItem(decItem);
    // It has to be rendered onto yet another pixmap or else DPI scaling will look terrible...
    QPixmap final(wWidth * ratio, wHeight * ratio);
    final.fill(QColor(0, 0, 0, 0));
Example #28
0
void HoleFinderPrivate::mergeHoles()
{
  // Make copy, clear original, add merged holes back into original
  QVector<Hole> holeCopy (this->holes);
  const int numHoles = this->holes.size();
  this->holes.clear();
  this->holes.reserve(numHoles);

  // If the bit is on, it has not been merged. If off, it has been.
  QBitArray mask (holeCopy.size(), true);

  // Check each pair of unmerged holes. If one contains the other, merge them.
  QVector<Hole*> toMerge;
  toMerge.reserve(256); // Way bigger than we need, but certainly sufficient

  // Temp vars
  Eigen::Vector3d diffVec;

  // "i" indexes the "base" hole
  for (int i = 0; i < numHoles; ++i) {
    if (!mask.testBit(i))
      continue;

    mask.clearBit(i);
    Hole &hole_i = holeCopy[i];

    toMerge.clear();
    toMerge.reserve(256);
    toMerge.push_back(&hole_i);

    // "j" indexes the compared holes
    for (int j = i+1; j < numHoles; ++j) {
      if (!mask.testBit(j))
        continue;

      Hole &hole_j = holeCopy[j];

      diffVec = hole_j.center - hole_i.center;

      // Use the greater of the two radii
      const double rad = (hole_i.radius > hole_j.radius)
          ? hole_i.radius : hole_j.radius;
      const double radSq = rad * rad;

      // Check periodic conditions
      // Convert diffVec to fractional units
      this->cartToFrac(&diffVec);
      // Adjust each component to range [-0.5, 0.5] (shortest representation)
      while (diffVec.x() < -0.5) ++diffVec.x();
      while (diffVec.y() < -0.5) ++diffVec.y();
      while (diffVec.z() < -0.5) ++diffVec.z();
      while (diffVec.x() > 0.5) --diffVec.x();
      while (diffVec.y() > 0.5) --diffVec.y();
      while (diffVec.z() > 0.5) --diffVec.z();
      // Back to cartesian
      this->fracToCart(&diffVec);

      // if j is within i's radius, add "j" to the merge list
      // and mark "j" as merged
      if (fabs(diffVec.x()) > rad ||
          fabs(diffVec.y()) > rad ||
          fabs(diffVec.z()) > rad ||
          fabs(diffVec.squaredNorm()) > radSq)
        continue; // no match

      // match:
      // Reset j's position to account for periodic wrap-around
      hole_j.center = hole_i.center + diffVec;
      mask.clearBit(j);
      toMerge.push_back(&hole_j);
    }

    if (toMerge.size() == 1)
      this->holes.push_back(hole_i);
    else
      this->holes.push_back(reduceHoles(toMerge));
  }
}
Example #29
0
void
VolumeMask::findConnectedRegion(QList<int> pos)
{
  QBitArray bitcopy = m_bitmask;
  m_bitmask.fill(false);


  QStack<int> stack;

  // put the seeds in
  for(int pi=0; pi<pos.size()/3; pi++)
    {
      int d = pos[3*pi];
      int w = pos[3*pi+1];
      int h = pos[3*pi+2];
      qint64 idx = d*m_width*m_height + w*m_height + h;
      if (bitcopy.testBit(idx))
	{
	  uchar mask;
	  uchar *mslice = m_maskFileManager.rawValue(d, w, h);
	  if (mslice)
	    mask = mslice[0];
	  
	  if (mask != Global::tag())
	    {
	      m_bitmask.setBit(idx);
	      stack.push(d);
	      stack.push(w);
	      stack.push(h);
	    }
	}
    }

  uchar tag = Global::tag();
  while(!stack.isEmpty())
    {
      int h = stack.pop();
      int w = stack.pop();
      int d = stack.pop();
      qint64 idx = d*m_width*m_height + w*m_height + h;
      if (bitcopy.testBit(idx))
	{
	  int d0 = qMax(d-1, 0);
	  int d1 = qMin(d+1, m_depth-1);
	  int w0 = qMax(w-1, 0);
	  int w1 = qMin(w+1, m_width-1);
	  int h0 = qMax(h-1, 0);
	  int h1 = qMin(h+1, m_height-1);
	      
	  for(int d2=d0; d2<=d1; d2++)
	    for(int w2=w0; w2<=w1; w2++)
	      for(int h2=h0; h2<=h1; h2++)
		{
		  uchar mask;
		  qint64 idx = d2*m_width*m_height +
		               w2*m_height + h2;
		  uchar *mslice = m_maskFileManager.rawValue(d2, w2, h2);
		  if (mslice)
		    mask = mslice[0];

		  if (tag == mask ||
		      (tag && !mask) ||
		      (!tag && mask) )
		    {
		      if (   bitcopy.testBit(idx) &&
			  !m_bitmask.testBit(idx) )
			{
			  m_bitmask.setBit(idx);
			  stack.push(d2);
			  stack.push(w2);
			  stack.push(h2);
			}
		    }
		}
	}
    } // end find connected
  //------------------------------------------------------
}
Example #30
0
void KeyWidget::paintEvent(QPaintEvent*){
    const QColor bgColor(68, 64, 64);
    const QColor keyColor(112, 110, 110);
    const QColor sniperColor(130, 90, 90);
    const QColor highlightColor(136, 176, 240);
    const QColor highlightAnimColor(136, 200, 240);
    const QColor animColor(112, 200, 110);

    // Determine which keys to highlight
    QBitArray highlight;
    switch(mouseDownMode){
    case SET:
        highlight = newSelection;
        break;
    case ADD:
        highlight = selection | newSelection;
        break;
    case SUBTRACT:
        highlight = selection & ~newSelection;
        break;
    case TOGGLE:
        highlight = selection ^ newSelection;
        break;
    default:
        highlight = selection;
    }

    QPainter painter(this);
#if QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)
    int ratio = painter.device()->devicePixelRatio();
#else
    int ratio = 1;
#endif
    int wWidth = width(), wHeight = height();
    KeyMap::Model model = keyMap.model();
    float scale, offX, offY;
    drawInfo(scale, offX, offY);
    // Draw background
    painter.setPen(Qt::NoPen);
    painter.setRenderHint(QPainter::Antialiasing, true);

    if(model == KeyMap::M65){
        // M65: Draw overlay
        if(!m65Overlay)
            m65Overlay = new QImage(":/img/overlay_m65.png");
        const QImage& overlay = *m65Overlay;
        painter.setBrush(palette().brush(QPalette::Window));
        painter.drawRect(0, 0, width(), height());
        float oXScale = scale / 9.f, oYScale = scale / 9.f;             // The overlay has a resolution of 9px per keymap unit
        float x = (2.f + offX) * scale, y = (-2.f + offY) * scale;      // It is positioned at (2, -2)
        int w = overlay.width() * oXScale, h = overlay.height() * oYScale;
        // We need to transform the image with QImage::scaled() because painter.drawImage() will butcher it, even with smoothing enabled
        // However, the width/height need to be rounded to integers
        int iW = round(w), iH = round(h);
        painter.drawImage(QRectF(x - (iW - w) / 2.f, y - (iH - h) / 2.f, iW, iH), overlay.scaled(iW, iH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
    } else {
        // Otherwise, draw a solid background
        painter.setBrush(QBrush(bgColor));
        painter.drawRect(0, 0, width(), height());
    }

    // Draw mouse highlight (if any)
    if(mouseDownMode != NONE && (mouseDownX != mouseCurrentX || mouseDownY != mouseCurrentY)){
        int x1 = (mouseDownX > mouseCurrentX) ? mouseCurrentX : mouseDownX;
        int x2 = (mouseDownX > mouseCurrentX) ? mouseDownX : mouseCurrentX;
        int y1 = (mouseDownY > mouseCurrentY) ? mouseCurrentY : mouseDownY;
        int y2 = (mouseDownY > mouseCurrentY) ? mouseDownY : mouseCurrentY;
        painter.setPen(QPen(highlightColor, 0.5));
        QColor bColor = highlightColor;
        bColor.setAlpha(128);
        painter.setBrush(QBrush(bColor));
        painter.drawRect(x1, y1, x2 - x1, y2 - y1);
    }

    // Draw key backgrounds on a separate pixmap so that a drop shadow can be applied to them.
    QPixmap keyBG(wWidth * ratio, wHeight * ratio);
    keyBG.fill(QColor(0, 0, 0, 0));
    QPainter bgPainter(&keyBG);
    bgPainter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
    bgPainter.setPen(Qt::NoPen);
    QHashIterator<QString, Key> k(keyMap);
    uint i = -1;
    while(k.hasNext()){
        k.next();
        i++;
        const Key& key = k.value();
        float x = key.x + offX - key.width / 2.f + 1.f;
        float y = key.y + offY - key.height / 2.f + 1.f;
        float w = key.width - 2.f;
        float h = key.height - 2.f;
        // In RGB mode, ignore keys without LEDs
        if((_rgbMode && !key.hasLed)
                || (!_rgbMode && !key.hasScan))
            continue;
        // Set color based on key highlight
        bgPainter.setOpacity(1.);
        if(highlight.testBit(i)){
            if(animation.testBit(i))
                bgPainter.setBrush(QBrush(highlightAnimColor));
            else
                bgPainter.setBrush(QBrush(highlightColor));
        } else if(animation.testBit(i)){
            bgPainter.setBrush(QBrush(animColor));
        } else {
            if(!strcmp(key.name, "sniper"))
                // Sniper key uses a reddish base color instead of the usual grey
                bgPainter.setBrush(QBrush(sniperColor));
            else {
                bgPainter.setBrush(QBrush(keyColor));
                if(KeyMap::isMouse(model))
                    bgPainter.setOpacity(0.7);
            }
        }
        if(!strcmp(key.name, "mr") || !strcmp(key.name, "m1") || !strcmp(key.name, "m2") || !strcmp(key.name, "m3")
                || !strcmp(key.name, "light") || !strcmp(key.name, "lock") || (model == KeyMap::K65 && !strcmp(key.name, "mute"))){
            // Switch keys are circular
            x += w / 8.f;
            y += h / 8.f;
            w *= 0.75f;
            h *= 0.75f;
            bgPainter.drawEllipse(QRectF(x * scale, y * scale, w * scale, h * scale));
        } else {
            if(!strcmp(key.name, "enter")){
                if(key.height == 24){
                    // ISO enter key isn't rectangular
                    y = key.y + 1.f;
                    h = 10.f;
                    bgPainter.drawRect(QRectF((x + w - 13.f) * scale, y * scale, 13.f * scale, 22.f * scale));
                } else {
                    // US enter key isn't perfectly centered, needs an extra pixel on the left to appear correctly
                    x -= 1.f;
                    w += 1.f;
                }
            } else if(!strcmp(key.name, "rshift") || !strcmp(key.name, "stop")){
                // A few other keys also need extra pixels
                x -= 1.f;
                w += 1.f;
            } else if(!strcmp(key.name, "caps") || !strcmp(key.name, "lshift") || !strcmp(key.name, "next")){
                w += 1.f;
            }
            bgPainter.drawRect(QRectF(x * scale, y * scale, w * scale, h * scale));
        }
    }

    // Render the key decorations (RGB -> light circles, binding -> key names) on yet another layer
    QPixmap decoration(wWidth * ratio, wHeight * ratio);
    decoration.fill(QColor(0, 0, 0, 0));
    QPainter decPainter(&decoration);
    decPainter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
    if(_rgbMode){
        // Draw key colors (RGB mode)
        decPainter.setPen(QPen(QColor(255, 255, 255), 1.5));
        QHashIterator<QString, Key> k(keyMap);
        uint i = -1;
        while(k.hasNext()){
            k.next();
            i++;
            const Key& key = k.value();
            if(!key.hasLed)
                continue;
            float x = key.x + offX - 1.8f;
            float y = key.y + offY - 1.8f;
            float w = 3.6f;
            float h = 3.6f;
            if(_displayColorMap.contains(key.name))
                decPainter.setBrush(QBrush(_displayColorMap.value(key.name)));
            else
                decPainter.setBrush(QBrush(_colorMap.value(key.name)));
            decPainter.drawEllipse(QRectF(x * scale, y * scale, w * scale, h * scale));
        }
    } else {
        // Draw key names
        decPainter.setBrush(Qt::NoBrush);
        QFont font = painter.font();
        font.setBold(true);
        font.setPixelSize(5.25f * scale);
        QFont font0 = font;
        QHashIterator<QString, Key> k(keyMap);
        uint i = -1;
        while(k.hasNext()){
            k.next();
            i++;
            const Key& key = k.value();
            if(!key.hasScan)
                continue;
            float x = key.x + offX - key.width / 2.f + 1.f;
            float y = key.y + offY - key.height / 2.f;
            float w = key.width - 2.f;
            float h = key.height;
            // Print the key's friendly name (with some exceptions)
            QString keyName = KbBind::globalRemap(key.name);
            QString name = key.friendlyName(false);
            name = name.split(" ").last();
            struct {
                const char* keyName, *displayName;
            } names[] = {
                {"light", "☼"}, {"lock", "☒"}, {"mute", "◖⊘"}, {"volup", keyMap.model() == KeyMap::K65 ? "◖))" : "▲"}, {"voldn", keyMap.model() == KeyMap::K65 ? "◖)" : "▼"},
                {"prtscn",  "PrtScn\nSysRq"}, {"scroll", "Scroll\nLock"}, {"pause", "Pause\nBreak"}, {"stop", "▪"}, {"prev", "|◂◂"}, {"play", "▸||"}, {"next", "▸▸|"},
                {"pgup", "Page\nUp"}, {"pgdn", "Page\nDown"}, {"numlock", "Num\nLock"},
                {"caps", "Caps"}, {"lshift", "Shift"}, {"rshift", "Shift"},
#ifdef Q_OS_MACX
                {"lctrl", "⌃"}, {"rctrl", "⌃"}, {"lwin", "⌘"}, {"rwin", "⌘"}, {"lalt", "⌥"}, {"ralt", "⌥"},
#else
                {"lctrl", "Ctrl"}, {"rctrl", "Ctrl"}, {"lwin", "❖"}, {"rwin", "❖"}, {"lalt", "Alt"}, {"ralt", "Alt"},
#endif
                {"rmenu", "▤"}, {"up", "▲"}, {"left", "◀"}, {"down", "▼"}, {"right", "▶"},
                {"mouse1", ""}, {"mouse2", ""}, {"mouse3", "∙"}, {"dpiup", "▲"}, {"dpidn", "▼"}, {"wheelup", "▲"}, {"wheeldn", "▼"}, {"dpi", "◉"}, {"mouse5", "▲"}, {"mouse4", "▼"}, {"sniper", "⊕"}
            };
            for(uint k = 0; k < sizeof(names) / sizeof(names[0]); k++){
                if(keyName == names[k].keyName){
                    name = names[k].displayName;
                    break;
                }
            }
            if(keyName == "mr" || keyName == "m1" || keyName == "m2" || keyName == "m3" || keyName == "up" || keyName == "down" || keyName == "left" || keyName == "right")
                // Use a smaller size for MR, M1 - M3, and arrow keys
                font.setPixelSize(font.pixelSize() * 0.75);
            else if(keyName == "end")
                // Use a smaller size for "End" to match everything else in that area
                font.setPixelSize(font.pixelSize() * 0.65);
            else if(keyName == "light"
#ifndef Q_OS_MACX
                    || keyName == "lwin" || keyName == "rwin"
#endif
                    )
                // Use a larger font size for Super (Linux only) and Brightness to compensate for the unicode symbols looking smaller
                font.setPixelSize(font.pixelSize() * 1.3);
            // Determine the appropriate size to draw the text at
            decPainter.setFont(font);
            QRectF rect(x * scale, y * scale - 1, w * scale, h * scale);
            int flags = Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextWordWrap;
            QRectF bounds = decPainter.boundingRect(rect, flags, name);
            while((bounds.height() >= rect.height() - 8. || bounds.width() >= rect.width() - 2.) && font.pixelSize() >= 5){
                // Scale font size down until it fits inside the key
                font.setPixelSize(font.pixelSize() - 2);
                decPainter.setFont(font);
                bounds = decPainter.boundingRect(rect, flags, name);
            }
            // Pick color based on key function
            QString bind = _bindMap.value(key.name);
            QString def = KbBind::defaultAction(key.name);
            if(bind.isEmpty())
                // Unbound - red
                decPainter.setPen(QColor(255, 136, 136));
            else if(KeyAction(bind).isProgram())
                // Custom program - orange
                decPainter.setPen(QColor(255, 224, 192));
            else if(KeyAction(bind).isSpecial() && (bind == def || !KeyAction(def).isSpecial()))
                // Special function - blue (only if not mapped to a different function - if a special function is remapped, color it yellow)
                decPainter.setPen(QColor(128, 224, 255));
            else if(KeyAction(bind).isMedia() && (bind == def || !KeyAction(def).isMedia()))
                // Media key - green
                decPainter.setPen(QColor(160, 255, 168));
            else if(bind == def)
                // Standard key - white
                decPainter.setPen(QColor(255, 255, 255));
            else
                // Remapped key - yellow
                decPainter.setPen(QColor(255, 248, 128));
            decPainter.drawText(rect, flags, name);
            font = font0;
        }
    }
    // Create drop shadow effects
    QGraphicsDropShadowEffect* bgEffect = new QGraphicsDropShadowEffect;  // Have to use "new", creating these on the stack causes a crash...
    bgEffect->setBlurRadius(2.);
    bgEffect->setColor(QColor(0, 0, 0, 32));
    bgEffect->setOffset(0, 1);
    QGraphicsDropShadowEffect* decEffect = new QGraphicsDropShadowEffect;
    decEffect->setBlurRadius(4.);
    decEffect->setColor(QColor(0, 0, 0, 104));
    decEffect->setOffset(0, 1);
    // Apply them to the pixmaps
    QGraphicsPixmapItem* bgItem = new QGraphicsPixmapItem(keyBG);
    bgItem->setGraphicsEffect(bgEffect);
    QGraphicsPixmapItem* decItem = new QGraphicsPixmapItem(decoration);
    decItem->setGraphicsEffect(decEffect);
    // Render everything
    QGraphicsScene* scene = new QGraphicsScene;
    scene->addItem(bgItem);
    scene->addItem(decItem);
    // It has to be rendered onto yet another pixmap or else DPI scaling will look terrible...
    QPixmap final(wWidth * ratio, wHeight * ratio);
    final.fill(QColor(0, 0, 0, 0));