diff --git a/atom.h b/atom.h index 975af25..5fe7bd0 100644 --- a/atom.h +++ b/atom.h @@ -1,70 +1,70 @@ /******************************************************************* * * Copyright (C) 1999 Stephan Kulow * * This file is part of the KDE project "KAtomic" * * KAtomic is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * KAtomic is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with KAtomic; see the file COPYING. If not, write to * the Free Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * ********************************************************************/ #ifndef ATOM_H #define ATOM_H #define MAX_CONNS_PER_ATOM 8 class atom { public: char obj; char conn[MAX_CONNS_PER_ATOM + 1]; - bool operator==(const atom& rhs) const { return (rhs.obj == obj && !strcmp(rhs.conn,conn)); } + bool operator==(atom rhs) const { return (rhs.obj == obj && !strcmp(rhs.conn,conn)); } bool isEmpty() const { return (obj == 0 || obj == '.'); } double weight() const { switch (obj) { case '1': return 1.00797; // H case '2': return 12.0107; // C case '3': return 15.9994; // O case '4': return 14.0067; // N case '5': return 32.065; // S case '6': return 18.9984; // Fl case '7': return 35.453; // Cl case '9': return 30.97; // P default: return 0.0; } } }; inline char int2atom(int i) { if (!i) return '.'; if (i == 254) return '#'; if (i <= 9) return i + '0'; return i + 'a' - 10; } inline int atom2int(char ch) { if (ch == '.' || ch == 0) return 0; if (ch == '#') return 254; if (ch >= '0' && ch <= '9') return ch - '0'; return ch - 'a' + 10; } #endif diff --git a/fielditem.cpp b/fielditem.cpp index 9064c8b..280aa8c 100644 --- a/fielditem.cpp +++ b/fielditem.cpp @@ -1,264 +1,264 @@ /******************************************************************* * * Copyright 2006 Dmitry Suzdalev * Copyright 2007 Carsten Niehaus * Copyright 2010 Brian Croom * * This file is part of the KDE project "KAtomic" * * KAtomic is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * KAtomic is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with KAtomic; see the file COPYING. If not, write to * the Free Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * ********************************************************************/ #include "fielditem.h" #include #include #include "molecule.h" #include "playfield.h" FieldItem::FieldItem( KGameRenderer* renderer, const QString& spriteKey, QGraphicsScene* scene ) : KGameRenderedItem( renderer, spriteKey ), m_fieldX(0), m_fieldY(0) { if( scene ) scene->addItem( this ); setShapeMode( BoundingRectShape ); } static const char* arrow_spriteKeys[] = {"arrow_Up", "arrow_Down", "arrow_Left", "arrow_Right"}; ArrowFieldItem::ArrowFieldItem( KGameRenderer* renderer, PlayField::Direction dir, QGraphicsScene* scene ) : FieldItem( renderer, QLatin1String(arrow_spriteKeys[dir]), scene ) { setOpacity(0.0); //start invisible m_timeLine = new QTimeLine(200); m_timeLine->setFrameRange( 0, 30 ); connect(m_timeLine, &QTimeLine::valueChanged, this, &ArrowFieldItem::setOpacity); } ArrowFieldItem::~ArrowFieldItem() { delete m_timeLine; } void ArrowFieldItem::setOpacity( qreal opacity ) { //NOTE: This method is only there because QGI::setOpacity is not a slot. QGraphicsItem::setOpacity(opacity); } QVariant ArrowFieldItem::itemChange( GraphicsItemChange change, const QVariant& value ) { if(change == ItemVisibleChange) { if(value.toBool()) { m_timeLine->stop(); m_timeLine->setCurrentTime(0); m_timeLine->start(); } } return value; } -AtomFieldItem::AtomFieldItem( KGameRenderer* renderer, const atom& at, QGraphicsScene* scene ) +AtomFieldItem::AtomFieldItem( KGameRenderer* renderer, atom at, QGraphicsScene* scene ) : FieldItem(renderer, s_names.value(at.obj), scene), m_atomNum(-1) { if(s_names.empty()) { fillNameHashes(); setSpriteKey(s_names.value(at.obj)); // It wasn't yet filled in when the constructor was called } // create the bonds as child items for (int c = 0; c < MAX_CONNS_PER_ATOM; c++) { char conn = at.conn[c]; if (!conn) break; KGameRenderedItem* bond = new KGameRenderedItem(renderer, s_bondNames.value(conn), this); bond->setFlag(QGraphicsItem::ItemStacksBehindParent); } } void AtomFieldItem::setRenderSize(const QSize& renderSize) { KGameRenderedItem::setRenderSize(renderSize); const QList bonds = childItems(); for (QGraphicsItem* item : bonds) { dynamic_cast(item)->setRenderSize(renderSize); } } QHash AtomFieldItem::s_names; QHash AtomFieldItem::s_bondNames; void AtomFieldItem::fillNameHashes() { s_names['1'] = QStringLiteral("atom_H"); s_names['2'] = QStringLiteral("atom_C"); s_names['3'] = QStringLiteral("atom_O"); s_names['4'] = QStringLiteral("atom_N"); s_names['5'] = QStringLiteral("atom_S"); s_names['6'] = QStringLiteral("atom_F"); s_names['7'] = QStringLiteral("atom_Cl"); s_names['8'] = QStringLiteral("atom_Br"); s_names['9'] = QStringLiteral("atom_P"); s_names['0'] = QStringLiteral("atom_J"); s_names['o'] = QStringLiteral("atom_Crystal"); s_names['A'] = QStringLiteral("connector_Hor"); s_names['B'] = QStringLiteral("connector_Slash"); s_names['C'] = QStringLiteral("connector_Ver"); s_names['D'] = QStringLiteral("connector_Backslash"); s_names['#'] = QStringLiteral("wall"); s_names['<'] = QStringLiteral("arrow_Left"); s_names['>'] = QStringLiteral("arrow_Right"); s_names['^'] = QStringLiteral("arrow_Up"); s_names['_'] = QStringLiteral("arrow_Down"); s_names['E'] = QStringLiteral("atom_flask0"); s_names['F'] = QStringLiteral("atom_flask1"); s_names['G'] = QStringLiteral("atom_flask2"); s_names['H'] = QStringLiteral("atom_flask3"); s_names['I'] = QStringLiteral("atom_flask4"); s_names['J'] = QStringLiteral("atom_flask5"); s_names['K'] = QStringLiteral("atom_flask6"); s_names['L'] = QStringLiteral("atom_flask7"); s_bondNames['a'] = QStringLiteral("bond_I_Top"); s_bondNames['b'] = QStringLiteral("bond_I_TopRight"); s_bondNames['c'] = QStringLiteral("bond_I_Right"); s_bondNames['d'] = QStringLiteral("bond_I_BotRight"); s_bondNames['e'] = QStringLiteral("bond_I_Bottom"); s_bondNames['f'] = QStringLiteral("bond_I_BotLeft"); s_bondNames['g'] = QStringLiteral("bond_I_Left"); s_bondNames['h'] = QStringLiteral("bond_I_TopLeft"); s_bondNames['A'] = QStringLiteral("bond_II_Top"); s_bondNames['B'] = QStringLiteral("bond_II_Right"); s_bondNames['C'] = QStringLiteral("bond_II_Bottom"); s_bondNames['D'] = QStringLiteral("bond_II_Left"); s_bondNames['E'] = QStringLiteral("bond_III_Top"); s_bondNames['F'] = QStringLiteral("bond_III_Right"); s_bondNames['G'] = QStringLiteral("bond_III_Bottom"); s_bondNames['H'] = QStringLiteral("bond_III_Left"); } -QPixmap AtomFieldItem::renderAtom( KGameRenderer* renderer, const atom& at, int size ) +QPixmap AtomFieldItem::renderAtom( KGameRenderer* renderer, atom at, int size ) { if (size == 0) return QPixmap(); QPixmap atomPix = renderer->spritePixmap(s_names.value(at.obj), QSize(size, size)); QPainter p; QPixmap bonds(size,size); bonds.fill(Qt::transparent); for (int c = 0; c < MAX_CONNS_PER_ATOM; c++) { char conn = at.conn[c]; if (!conn) break; QPixmap pix = renderer->spritePixmap(s_bondNames.value(conn), QSize(size, size)); p.begin(&bonds); p.drawPixmap(0,0, pix); p.end(); } p.begin(&bonds); p.drawPixmap(0,0, atomPix); p.end(); return bonds; } // ----------------- MoleculePreviewItem ---------------------------- MoleculePreviewItem::MoleculePreviewItem( PlayField* scene ) : QGraphicsItem( nullptr ), m_renderer(scene->renderer()), m_width(0), m_atomSize(20), m_maxAtomSize(30), m_mol( nullptr ) { scene->addItem(this); } MoleculePreviewItem::~MoleculePreviewItem() { } void MoleculePreviewItem::setMolecule( const Molecule* mol ) { m_mol = mol; setWidth( m_width ); // trigger atom size update } void MoleculePreviewItem::setMaxAtomSize(int maxSize) { m_maxAtomSize = maxSize; setWidth( m_width ); // trigger atom size update } void MoleculePreviewItem::setWidth(int width) { m_width = width; if(!m_mol) return; int w = m_mol->width(); int h = m_mol->height(); int atomSize = width / qMax(w,h); m_atomSize = qMin(atomSize, m_maxAtomSize); update(); } void MoleculePreviewItem::paint( QPainter * painter, const QStyleOptionGraphicsItem*, QWidget *) { if ( m_width == 0 || m_mol == nullptr ) return; painter->save(); painter->setBrush(Qt::gray); painter->setOpacity(0.5); painter->drawRect(boundingRect()); painter->setOpacity(1.0); int originX = m_width/2 - m_atomSize*m_mol->width()/2; int originY = m_width/2 - m_atomSize*m_mol->height()/2; // Paint the playing field for (int i = 0; i < MOLECULE_SIZE; i++) for (int j = 0; j < MOLECULE_SIZE; j++) { int x = originX + i * m_atomSize; int y = originY + j * m_atomSize; if (m_mol->getAtom(i,j) == 0) continue; int atomIdx = m_mol->getAtom(i,j); QPixmap aPix = AtomFieldItem::renderAtom(m_renderer, m_mol->getAtom(atomIdx), m_atomSize); painter->drawPixmap(x, y, aPix); } painter->restore(); } diff --git a/fielditem.h b/fielditem.h index e99b8d0..feff3e1 100644 --- a/fielditem.h +++ b/fielditem.h @@ -1,168 +1,168 @@ /******************************************************************* * * Copyright 2006-2007 Dmitry Suzdalev * Copyright 2010 Brian Croom * * This file is part of the KDE project "KAtomic" * * KAtomic is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * KAtomic is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with KAtomic; see the file COPYING. If not, write to * the Free Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * ********************************************************************/ #ifndef FIELD_ITEM_H #define FIELD_ITEM_H #include #include #include "playfield.h" // for enum PlayField::Direction class KGameRenderer; class atom; /** * Represents item that can be placed in the PlayField. * Basically it just extends QGraphicsPixmapItem by understanding * field's cellbased coords. */ class FieldItem : public KGameRenderedItem { public: explicit FieldItem( KGameRenderer* renderer, const QString& spriteKey, QGraphicsScene* scene ); void setFieldX(int x) { m_fieldX = x; } void setFieldY(int y) { m_fieldY = y; } void setFieldXY(int x, int y) { m_fieldX = x; m_fieldY = y; } int fieldX() const { return m_fieldX; } int fieldY() const { return m_fieldY; } // enable use of qgraphicsitem_cast enum { Type = UserType + 1 }; int type() const override { return Type; } private: int m_fieldX; int m_fieldY; }; /** * FieldItem that knows what atom number it holds * @see Molecule */ class AtomFieldItem : public FieldItem { public: - explicit AtomFieldItem( KGameRenderer* renderer, const atom& at, QGraphicsScene* scene ); + explicit AtomFieldItem(KGameRenderer* renderer, atom at, QGraphicsScene* scene ); void setAtomNum(int n) { m_atomNum = n; } int atomNum() const { return m_atomNum; } /** * Override so that the bonds (child objects) have their render size * adjusted too */ void setRenderSize(const QSize& renderSize); /** * Statically render the atom, for MoleculePreviewItem */ - static QPixmap renderAtom( KGameRenderer* renderer, const atom& at, int size); + static QPixmap renderAtom(KGameRenderer* renderer, atom at, int size); // enable use of qgraphicsitem_cast enum { Type = UserType + 2 }; int type() const override { return Type; } private: // from molecule int m_atomNum; static QHash s_names; // cryptic_char -> elemName static QHash s_bondNames; // cryptic_char -> bondName /** * Creates hashes for translating atom and bond signatures found in * level files to corresponding SVG-element names */ static void fillNameHashes(); }; class QTimeLine; /** * FieldItem that represents clickable arrow. * While showing plays nice fade-in effect */ class ArrowFieldItem : public QObject, public FieldItem { Q_OBJECT public: explicit ArrowFieldItem( KGameRenderer* renderer, PlayField::Direction dir, QGraphicsScene* scene ); ~ArrowFieldItem() override; // enable use of qgraphicsitem_cast enum { Type = UserType + 3 }; int type() const override { return Type; } private Q_SLOTS: void setOpacity( qreal opacity ); private: QVariant itemChange( GraphicsItemChange change, const QVariant& value ) override; /** * Timeline object to control fade-in animation */ QTimeLine *m_timeLine; }; class Molecule; class PlayField; /** * QGraphicsItem which displays molecule preview. */ class MoleculePreviewItem : public QGraphicsItem { public: explicit MoleculePreviewItem( PlayField* scene ); ~MoleculePreviewItem() override; /** * Sets molecule to display */ void setMolecule( const Molecule* mol ); /** * Sets item width. Height will be calculated automatically */ void setWidth( int width ); /** * Sets maximum atom size in rendered molecule preview. * Usually atom size is calculated so the whole molecule can fit * in the item. * In some cases - when item width is big and the molecule is small this * can lead to preview having a huge molecule with atom size larger than * in playfield :). That looks not very good, hence this function. */ void setMaxAtomSize( int maxSize ); inline QRectF boundingRect() const override { return QRectF(0,0, m_width, m_width); } // reimp private: void paint( QPainter * painter, const QStyleOptionGraphicsItem*, QWidget * widget = nullptr ) override; KGameRenderer* m_renderer; int m_width; int m_atomSize; int m_maxAtomSize; const Molecule* m_mol; }; #endif diff --git a/levelsetdelegate.h b/levelsetdelegate.h index 42ae1a1..af0252e 100644 --- a/levelsetdelegate.h +++ b/levelsetdelegate.h @@ -1,40 +1,41 @@ /******************************************************************* * * Copyright 2006-2009 Dmitry Suzdalev * * This file is part of the KDE project "KAtomic" * * KAtomic is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * KAtomic is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with KAtomic; see the file COPYING. If not, write to * the Free Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * ********************************************************************/ #ifndef LEVEL_SET_DELEGATE_H #define LEVEL_SET_DELEGATE_H #include class LevelSetDelegate : public QStyledItemDelegate { + Q_OBJECT public: explicit LevelSetDelegate(QObject* parent = nullptr); void paint(QPainter* p, const QStyleOptionViewItem& option, const QModelIndex& index) const override; QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override; private: mutable int m_lineHeight; }; #endif