File indexing completed on 2024-04-21 04:01:59

0001 /*
0002     This file is part of the KDE project "KAtomic"
0003 
0004     SPDX-FileCopyrightText: 2006 Dmitry Suzdalev <dimsuz@gmail.com>
0005     SPDX-FileCopyrightText: 2007 Carsten Niehaus <cniehaus@kde.org>
0006     SPDX-FileCopyrightText: 2010 Brian Croom <brian.s.croom@gmail.com>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "fielditem.h"
0012 
0013 #include "molecule.h"
0014 
0015 #include <QApplication>
0016 #include <QPainter>
0017 #include <QTimeLine>
0018 
0019 FieldItem::FieldItem( KGameRenderer* renderer, const QString& spriteKey, QGraphicsScene* scene )
0020     : KGameRenderedItem( renderer, spriteKey ), m_fieldX(0), m_fieldY(0)
0021 {
0022     if( scene )
0023         scene->addItem( this );
0024     setShapeMode( BoundingRectShape );
0025 }
0026 
0027 
0028 static const char* arrow_spriteKeys[] = {"arrow_Up", "arrow_Down", "arrow_Left", "arrow_Right"};
0029 
0030 ArrowFieldItem::ArrowFieldItem( KGameRenderer* renderer, PlayField::Direction dir, QGraphicsScene* scene )
0031     : FieldItem( renderer, QLatin1String(arrow_spriteKeys[dir]), scene )
0032 {
0033     setOpacity(0.0); //start invisible
0034     m_timeLine = new QTimeLine(200);
0035     m_timeLine->setFrameRange( 0, 30 );
0036     connect(m_timeLine, &QTimeLine::valueChanged, this, &ArrowFieldItem::setOpacity);
0037 }
0038 
0039 ArrowFieldItem::~ArrowFieldItem()
0040 {
0041     delete m_timeLine;
0042 }
0043 
0044 void ArrowFieldItem::setOpacity( qreal opacity )
0045 {
0046     //NOTE: This method is only there because QGI::setOpacity is not a slot.
0047     QGraphicsItem::setOpacity(opacity);
0048 }
0049 
0050 QVariant ArrowFieldItem::itemChange( GraphicsItemChange change, const QVariant& value )
0051 {
0052     if(change == ItemVisibleChange)
0053     {
0054         if(value.toBool())
0055         {
0056             m_timeLine->stop();
0057             m_timeLine->setCurrentTime(0);
0058             m_timeLine->start();
0059         }
0060     }
0061     return value;
0062 }
0063 
0064 
0065 
0066 AtomFieldItem::AtomFieldItem( KGameRenderer* renderer, atom at, QGraphicsScene* scene )
0067     : FieldItem(renderer, s_names.value(at.obj), scene), m_atomNum(-1)
0068 {
0069     if(s_names.empty())
0070     {
0071         fillNameHashes();
0072         setSpriteKey(s_names.value(at.obj)); // It wasn't yet filled in when the constructor was called
0073     }
0074 
0075     // create the bonds as child items
0076     for (int c = 0; c < MAX_CONNS_PER_ATOM; c++)
0077     {
0078         char conn = at.conn[c];
0079         if (!conn)
0080             break;
0081 
0082         KGameRenderedItem* bond = new KGameRenderedItem(renderer, s_bondNames.value(conn), this);
0083         bond->setFlag(QGraphicsItem::ItemStacksBehindParent);
0084     }
0085 }
0086 
0087 void AtomFieldItem::setRenderSize(const QSize& renderSize)
0088 {
0089     KGameRenderedItem::setRenderSize(renderSize);
0090 
0091     const QList<QGraphicsItem*> bonds = childItems();
0092     for (QGraphicsItem* item : bonds)
0093     {
0094         dynamic_cast<KGameRenderedItem*>(item)->setRenderSize(renderSize);
0095     }
0096 }
0097 
0098 QHash<char, QString> AtomFieldItem::s_names;
0099 QHash<char, QString> AtomFieldItem::s_bondNames;
0100 
0101 void AtomFieldItem::fillNameHashes()
0102 {
0103     s_names['1'] = QStringLiteral("atom_H");
0104     s_names['2'] = QStringLiteral("atom_C");
0105     s_names['3'] = QStringLiteral("atom_O");
0106     s_names['4'] = QStringLiteral("atom_N");
0107     s_names['5'] = QStringLiteral("atom_S");
0108     s_names['6'] = QStringLiteral("atom_F");
0109     s_names['7'] = QStringLiteral("atom_Cl");
0110     s_names['8'] = QStringLiteral("atom_Br");
0111     s_names['9'] = QStringLiteral("atom_P");
0112     s_names['0'] = QStringLiteral("atom_J");
0113     s_names['o'] = QStringLiteral("atom_Crystal");
0114     s_names['A'] = QStringLiteral("connector_Hor");
0115     s_names['B'] = QStringLiteral("connector_Slash");
0116     s_names['C'] = QStringLiteral("connector_Ver");
0117     s_names['D'] = QStringLiteral("connector_Backslash");
0118     s_names['#'] = QStringLiteral("wall");
0119     s_names['<'] = QStringLiteral("arrow_Left");
0120     s_names['>'] = QStringLiteral("arrow_Right");
0121     s_names['^'] = QStringLiteral("arrow_Up");
0122     s_names['_'] = QStringLiteral("arrow_Down");
0123     s_names['E'] = QStringLiteral("atom_flask0");
0124     s_names['F'] = QStringLiteral("atom_flask1");
0125     s_names['G'] = QStringLiteral("atom_flask2");
0126     s_names['H'] = QStringLiteral("atom_flask3");
0127     s_names['I'] = QStringLiteral("atom_flask4");
0128     s_names['J'] = QStringLiteral("atom_flask5");
0129     s_names['K'] = QStringLiteral("atom_flask6");
0130     s_names['L'] = QStringLiteral("atom_flask7");
0131 
0132     s_bondNames['a'] = QStringLiteral("bond_I_Top");
0133     s_bondNames['b'] = QStringLiteral("bond_I_TopRight");
0134     s_bondNames['c'] = QStringLiteral("bond_I_Right");
0135     s_bondNames['d'] = QStringLiteral("bond_I_BotRight");
0136     s_bondNames['e'] = QStringLiteral("bond_I_Bottom");
0137     s_bondNames['f'] = QStringLiteral("bond_I_BotLeft");
0138     s_bondNames['g'] = QStringLiteral("bond_I_Left");
0139     s_bondNames['h'] = QStringLiteral("bond_I_TopLeft");
0140 
0141     s_bondNames['A'] = QStringLiteral("bond_II_Top");
0142     s_bondNames['B'] = QStringLiteral("bond_II_Right");
0143     s_bondNames['C'] = QStringLiteral("bond_II_Bottom");
0144     s_bondNames['D'] = QStringLiteral("bond_II_Left");
0145 
0146     s_bondNames['E'] = QStringLiteral("bond_III_Top");
0147     s_bondNames['F'] = QStringLiteral("bond_III_Right");
0148     s_bondNames['G'] = QStringLiteral("bond_III_Bottom");
0149     s_bondNames['H'] = QStringLiteral("bond_III_Left");
0150 }
0151 
0152 QPixmap AtomFieldItem::renderAtom( KGameRenderer* renderer, atom at, int size )
0153 {
0154     if (size == 0) return QPixmap();
0155 
0156     QPixmap atomPix = renderer->spritePixmap(s_names.value(at.obj), QSize(size, size));
0157 
0158     const qreal dpr = qApp->devicePixelRatio();
0159 
0160     QPainter p;
0161     QPixmap bonds(size * dpr, size * dpr);
0162     bonds.setDevicePixelRatio(dpr);
0163     bonds.fill(Qt::transparent);
0164     for (int c = 0; c < MAX_CONNS_PER_ATOM; c++)
0165     {
0166         char conn = at.conn[c];
0167         if (!conn)
0168             break;
0169 
0170         QPixmap pix = renderer->spritePixmap(s_bondNames.value(conn), QSize(size, size));
0171 
0172         p.begin(&bonds);
0173         p.drawPixmap(0,0, pix);
0174         p.end();
0175     }
0176 
0177     p.begin(&bonds);
0178     p.drawPixmap(0,0, atomPix);
0179     p.end();
0180     return bonds;
0181 }
0182 
0183 // ----------------- MoleculePreviewItem ----------------------------
0184 
0185 MoleculePreviewItem::MoleculePreviewItem( PlayField* scene )
0186     : QGraphicsItem( nullptr ), m_renderer(scene->renderer()), m_width(0),
0187     m_atomSize(20), m_maxAtomSize(30), m_mol( nullptr )
0188 {
0189     scene->addItem(this);
0190 }
0191 
0192 MoleculePreviewItem::~MoleculePreviewItem()
0193 {
0194 }
0195 
0196 void MoleculePreviewItem::setMolecule( const Molecule* mol )
0197 {
0198     m_mol = mol;
0199     setWidth( m_width ); // trigger atom size update
0200 }
0201 
0202 void MoleculePreviewItem::setMaxAtomSize(int maxSize)
0203 {
0204     m_maxAtomSize = maxSize;
0205     setWidth( m_width ); // trigger atom size update
0206 }
0207 
0208 void MoleculePreviewItem::setWidth(int width)
0209 {
0210     m_width = width;
0211 
0212     if(!m_mol)
0213         return;
0214     int w = m_mol->width();
0215     int h = m_mol->height();
0216     int atomSize = width / qMax(w,h);
0217     m_atomSize = qMin(atomSize, m_maxAtomSize);
0218     update();
0219 }
0220 
0221 void MoleculePreviewItem::paint( QPainter * painter, const QStyleOptionGraphicsItem*, QWidget *)
0222 {
0223     if ( m_width == 0 || m_mol == nullptr )
0224         return;
0225 
0226     painter->save();
0227     painter->setBrush(Qt::gray);
0228     painter->setOpacity(0.5);
0229     painter->drawRect(boundingRect());
0230     painter->setOpacity(1.0);
0231 
0232     int originX = m_width/2 - m_atomSize*m_mol->width()/2;
0233     int originY = m_width/2 - m_atomSize*m_mol->height()/2;
0234 
0235     // Paint the playing field
0236     for (int i = 0; i < MOLECULE_SIZE; i++)
0237         for (int j = 0; j < MOLECULE_SIZE; j++)
0238         {
0239             int x = originX + i * m_atomSize;
0240             int y = originY + j * m_atomSize;
0241 
0242             if (m_mol->getAtom(i,j) == 0)
0243                 continue;
0244 
0245             int atomIdx = m_mol->getAtom(i,j);
0246             QPixmap aPix = AtomFieldItem::renderAtom(m_renderer, m_mol->getAtom(atomIdx), m_atomSize);
0247             painter->drawPixmap(x, y, aPix);
0248         }
0249     painter->restore();
0250 }
0251 
0252 #include "moc_fielditem.cpp"