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"