File indexing completed on 2024-04-14 14:32:01

0001 // Copyright (c) 2002-2003 Rob Kaper <cap@capsi.com>
0002 //
0003 // This library is free software; you can redistribute it and/or
0004 // modify it under the terms of the GNU Lesser General Public
0005 // License version 2.1 as published by the Free Software Foundation.
0006 //
0007 // This library is distributed in the hope that it will be useful,
0008 // but WITHOUT ANY WARRANTY; without even the implied warranty of
0009 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0010 // Lesser General Public License for more details.
0011 //
0012 // You should have received a copy of the GNU Lesser General Public License
0013 // along with this library; see the file COPYING.LIB.  If not, write to
0014 // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0015 // Boston, MA 02110-1301, USA.
0016 
0017 #include <qpainter.h>
0018 #include <QPixmap>
0019 #include <QMouseEvent>
0020 #include <QLinearGradient>
0021 #include <QMenu>
0022 #include <QStandardPaths>
0023 #include <QFontDatabase>
0024 #include <QPaintEvent>
0025 #include <QTransform>
0026 
0027 #include <klocalizedstring.h>
0028 
0029 #include <player.h>
0030 #include <estate.h>
0031 
0032 #include "portfolioestate.h"
0033 
0034 #include "estateview.h"
0035 
0036 EstateView::EstateView(Estate *estate, EstateOrientation orientation, const QString &_icon, bool indicateUnowned,
0037                        bool highlightUnowned, bool darkenMortgaged, bool quartzEffects, QWidget *parent)
0038     : QWidget(parent)
0039     , m_estate(estate)
0040     , qpixmap(nullptr)
0041     , icon(nullptr)
0042     , m_quartzBlocks(nullptr)
0043     , m_pe(nullptr)
0044     , m_allowEstateSales(false)
0045     , m_indicateUnowned(indicateUnowned)
0046     , m_highlightUnowned(highlightUnowned)
0047     , m_darkenMortgaged(darkenMortgaged)
0048     , m_quartzEffects(quartzEffects)
0049     , b_recreate(true)
0050     , m_recreateQuartz(true)
0051     , m_orientation(orientation)
0052     , m_estateColor(m_estate->color())
0053 {
0054         setAttribute(Qt::WA_NoSystemBackground, true);
0055 
0056     updatePE();
0057 
0058     loadIcon(_icon);
0059 
0060     updateToolTip();
0061 }
0062 
0063 EstateView::~EstateView()
0064 {
0065     delete qpixmap;
0066     delete icon;
0067     delete m_quartzBlocks;
0068     delete m_pe;
0069 }
0070 
0071 void EstateView::updateToolTip()
0072 {
0073         QString toolTip = m_estate->name();
0074         if ( m_estate->isOwned() )
0075         {
0076             toolTip.append( QLatin1Char('\n') + i18n("Owner: %1", m_estate->owner()->name() ) );
0077             if ( m_estate->isMortgaged() )
0078                 toolTip.append( QLatin1Char('\n') + i18n("Unmortgage Price: %1", m_estate->unmortgagePrice() ) );
0079                 else
0080                     toolTip.append( QLatin1Char('\n') + i18n("Mortgage Value: %1", m_estate->mortgagePrice() ) );
0081             if ( m_estate->canSellHouses() )
0082                 toolTip.append( QLatin1Char('\n') + i18n("House Value: %1", m_estate->houseSellPrice() ) );
0083             if ( m_estate->canBuyHouses() )
0084                 toolTip.append( QLatin1Char('\n') + i18n("House Price: %1", m_estate->housePrice() ) );
0085         }
0086         else if ( m_estate->canBeOwned() )
0087             toolTip.append( QLatin1Char('\n') + i18n("Price: %1", m_estate->price() ) );
0088         else if ( m_estate->money() )
0089             toolTip.append( QLatin1Char('\n') + i18n("Money: %1", m_estate->money() ) );
0090 
0091         this->setToolTip( toolTip );
0092 }
0093 
0094 void EstateView::loadIcon(const QString &_icon)
0095 {
0096     m_estateIcon = QString();
0097     delete icon;
0098     icon = nullptr;
0099     if (_icon.isEmpty())
0100         return;
0101     const QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("atlantik/pics/") + _icon);
0102     if (path.isEmpty())
0103         return;
0104     icon = new QPixmap(path);
0105     if (icon->isNull())
0106     {
0107         delete icon;
0108         icon = nullptr;
0109     }
0110     else
0111     {
0112         icon = rotatePixmap(icon);
0113         m_estateIcon = _icon;
0114     }
0115 }
0116 
0117 void EstateView::setViewProperties(bool indicateUnowned, bool highlightUnowned, bool darkenMortgaged, bool quartzEffects)
0118 {
0119     if (m_indicateUnowned != indicateUnowned)
0120     {
0121         m_indicateUnowned = indicateUnowned;
0122         b_recreate = true;
0123         updatePE();
0124     }
0125 
0126     if (m_highlightUnowned != highlightUnowned)
0127     {
0128         m_highlightUnowned = highlightUnowned;
0129         b_recreate = true;
0130     }
0131 
0132     if (m_darkenMortgaged != darkenMortgaged)
0133     {
0134         m_darkenMortgaged = darkenMortgaged;
0135         b_recreate = true;
0136     }
0137 
0138     if (m_quartzEffects != quartzEffects)
0139     {
0140         m_quartzEffects = quartzEffects;
0141         m_recreateQuartz = true;
0142     }
0143 
0144     if (b_recreate || m_recreateQuartz)
0145         update();
0146 }
0147 
0148 QPixmap *EstateView::rotatePixmap(QPixmap *p) const
0149 {
0150     if (p==nullptr || p->isNull())
0151         return nullptr;
0152 
0153     QTransform m;
0154 
0155     switch(m_orientation)
0156     {
0157         case East:
0158             m.rotate(90);
0159             break;
0160         case West:
0161             m.rotate(-90);
0162             break;
0163         case South:
0164             m.rotate(180);
0165             break;
0166         default:;
0167     }
0168     *p = p->transformed(m);
0169     return p;
0170 }
0171 
0172 void EstateView::updatePE()
0173 {
0174     // Don't show a when a property is not unowned, cannot be owned at all
0175     // or when the user has configured Atlantik not to show them.
0176     if (m_estate->isOwned() || !m_estate->canBeOwned() || m_indicateUnowned==false)
0177     {
0178         delete m_pe;
0179         m_pe = nullptr;
0180     }
0181     else if (!m_pe)
0182     {
0183         // Display a coloured portfolioestate to indicate property is
0184         // for sale
0185         m_pe = new QPixmap(PortfolioEstate::drawPixmap(m_estate, nullptr, true));
0186     }
0187 }
0188 
0189 void EstateView::setAllowEstateSales(bool allow)
0190 {
0191     m_allowEstateSales = allow;
0192 }
0193 
0194 void EstateView::estateChanged()
0195 {
0196     updateToolTip();
0197     if (m_estate->icon() != m_estateIcon)
0198         loadIcon(m_estate->icon());
0199 
0200     if (m_estate->color() != m_estateColor)
0201         m_recreateQuartz = true;
0202     b_recreate = true;
0203 
0204     m_estateColor = m_estate->color();
0205 
0206     update();
0207     updatePE();
0208 }
0209 
0210 void EstateView::paintEvent(QPaintEvent *e)
0211 {
0212     m_titleHeight = height()/4;
0213     m_titleWidth = width()/4;
0214 
0215     if (m_recreateQuartz)
0216     {
0217         if (m_quartzBlocks)
0218         {
0219             delete m_quartzBlocks;
0220             m_quartzBlocks = nullptr;
0221         }
0222 
0223         if (m_quartzEffects && m_estateColor.isValid())
0224         {
0225             if (m_orientation == North || m_orientation == South)
0226                 m_quartzBlocks = new QPixmap(25, m_titleHeight-2);
0227             else
0228                 m_quartzBlocks = new QPixmap(25, m_titleWidth-2);
0229 
0230             drawQuartzBlocks(m_quartzBlocks, m_estateColor.lighter(60), m_estateColor);
0231             m_quartzBlocks = rotatePixmap(m_quartzBlocks);
0232         }
0233 
0234         m_recreateQuartz = false;
0235         b_recreate = true;
0236     }
0237 
0238     if (b_recreate)
0239     {
0240         if (!qpixmap || qpixmap->size() != size())
0241         {
0242             delete qpixmap;
0243             qpixmap = new QPixmap(width(), height());
0244         }
0245 
0246         QColor greenHouse(0, 255, 0);
0247         QColor redHotel(255, 51, 51);
0248         QPainter painter;
0249         painter.begin( qpixmap );
0250 
0251         painter.setPen(Qt::black);
0252 
0253         if (m_darkenMortgaged==true && m_estate->isMortgaged())
0254             painter.setBrush(m_estate->bgColor().lighter(10));
0255         else if (m_highlightUnowned==true && m_estate->canBeOwned() && !m_estate->isOwned())
0256             painter.setBrush(m_estate->bgColor().lighter(190));
0257         else
0258             painter.setBrush(m_estate->bgColor());
0259 
0260         painter.drawRect(rect().adjusted(0, 0, -1, -1));
0261 
0262         // Paint icon only when it exists and fits
0263         if (icon!=nullptr && width() > icon->width() && height() > icon->height())
0264             painter.drawPixmap( (width() - icon->width())/2, (height() - icon->height())/2, *icon);
0265 
0266         if (m_estateColor.isValid())
0267         {
0268             painter.setBrush(m_estateColor);
0269             switch(m_orientation)
0270             {
0271                 case North:
0272                     painter.drawRect(0, 0, width()-1, m_titleHeight-1);
0273 
0274                     if (m_quartzEffects && m_quartzBlocks)
0275                     {
0276                         painter.drawPixmap(1, 1, *m_quartzBlocks);
0277                     }
0278 
0279                     if (m_estate->houses() > 0)
0280                     {
0281                         if (m_estate->houses() == 5)
0282                         {
0283                             // Hotel
0284                             painter.setBrush(redHotel);
0285                             painter.drawRect(2, 2, (width()/2)-4-1, (m_titleHeight)-4-1);
0286                         }
0287                         else
0288                         {
0289                             // Houses
0290                             painter.setBrush(greenHouse);
0291                             int h = (m_titleHeight)-4, w = (m_titleWidth)-4;
0292                             for( unsigned int i=0 ; i < m_estate->houses() ; i++ )
0293                                 painter.drawRect(2+(i*(w+2)), 2, w-1, h-1);
0294                         }
0295                     }
0296                     break;
0297                 case South:
0298                     painter.drawRect(0, height()-(m_titleHeight), width()-1, m_titleHeight-1);
0299 
0300                     if (m_quartzEffects && m_quartzBlocks)
0301                     {
0302                         painter.drawPixmap(width()-m_quartzBlocks->width()-1, height()-m_titleHeight+1, *m_quartzBlocks);
0303                     }
0304 
0305                     if (m_estate->houses() > 0)
0306                     {
0307                         if (m_estate->houses() == 5)
0308                         {
0309                             // Hotel
0310                             painter.setBrush(redHotel);
0311                             painter.drawRect(2, (3*(m_titleHeight))+2, (width()/2)-4-1, (m_titleHeight)-4-1);
0312                         }
0313                         else
0314                         {
0315                             // Houses
0316                             painter.setBrush(greenHouse);
0317                             int h = (m_titleHeight)-4, w = (m_titleWidth)-4;
0318                             for( unsigned int i=0 ; i < m_estate->houses() ; i++ )
0319                                 painter.drawRect(2+(i*(w+2)), (3*(m_titleHeight))+2, w-1, h-1);
0320                         }
0321                     }
0322                     break;
0323                 case West:
0324                     painter.drawRect(0, 0, m_titleWidth-1, height()-1);
0325 
0326                     if (m_quartzEffects && m_quartzBlocks)
0327                     {
0328                         painter.drawPixmap(1, height()-m_quartzBlocks->height()-1, *m_quartzBlocks);
0329                     }
0330 
0331                     if (m_estate->houses() > 0)
0332                     {
0333                         if (m_estate->houses() == 5)
0334                         {
0335                             // Hotel
0336                             painter.setBrush(redHotel);
0337                             painter.drawRect(2, 2, (m_titleWidth)-4-1, (height()/2)-4-1);
0338                         }
0339                         else
0340                         {
0341                             // Houses
0342                             painter.setBrush(greenHouse);
0343                             int h = (m_titleHeight)-4, w = (m_titleWidth)-4;
0344                             for( unsigned int i=0 ; i < m_estate->houses() ; i++ )
0345                                 painter.drawRect(2, 2+(i*(h+2)), w-1, h-1);
0346                         }
0347                     }
0348                     break;
0349                 case East:
0350                     painter.drawRect(width()-(m_titleWidth), 0, m_titleWidth-1, height()-1);
0351 
0352                     if (m_quartzEffects && m_quartzBlocks)
0353                     {
0354                         painter.drawPixmap(width()-m_quartzBlocks->width()-1, 1, *m_quartzBlocks);
0355                     }
0356 
0357                     if (m_estate->houses() > 0)
0358                     {
0359                         if (m_estate->houses() == 5)
0360                         {
0361                             // Hotel
0362                             painter.setBrush(redHotel);
0363                             painter.drawRect((3*(m_titleWidth))+2, 2, (m_titleWidth)-4-1, (height()/2)-4-1);
0364                         }
0365                         else
0366                         {
0367                             // Houses
0368                             painter.setBrush(greenHouse);
0369                             int h = (m_titleHeight)-4, w = (m_titleWidth)-4;
0370                             for( unsigned int i=0 ; i < m_estate->houses() ; i++ )
0371                                 painter.drawRect((3*(m_titleWidth))+2, 2+(i*(h+2)), w-1, h-1);
0372                         }
0373                     }
0374                     break;
0375             }
0376         }
0377 
0378         const QFont font = QFontDatabase::systemFont(QFontDatabase::GeneralFont);
0379         painter.setFont(font);
0380         QString estateName = m_estate->name();
0381         QFontMetrics fm( font );
0382         if ( m_estateColor.isValid() && ( m_orientation == West || m_orientation == East ) )
0383         {
0384             estateName = fm.elidedText( m_estate->name(), Qt::ElideRight, 3*width()/4 );
0385         }
0386         else
0387             estateName = fm.elidedText( m_estate->name(), Qt::ElideRight,width() );
0388         if (m_estateColor.isValid() && m_orientation == West)
0389                         painter.drawText( width()/4 + 2, height()/2, estateName );
0390         else
0391             painter.drawText(2, height()/2, estateName );
0392 
0393         if (m_pe)
0394         {
0395             int x = (m_orientation == West ? (width()-2 - m_pe->width()) : 2);
0396             int y = (m_orientation == North ? (height()-2 - m_pe->height()) : 2);
0397             painter.drawPixmap(x, y, *m_pe);
0398         }
0399 
0400         b_recreate = false;
0401     }
0402     QPainter painter(this);
0403     painter.drawPixmap(e->rect(), *qpixmap, e->rect());
0404 }
0405 
0406 void EstateView::resizeEvent(QResizeEvent *)
0407 {
0408     m_recreateQuartz = true;
0409     b_recreate = true;
0410 }
0411 
0412 void EstateView::contextMenuEvent(QContextMenuEvent *e)
0413 {
0414     if (m_estate->isOwned())
0415     {
0416         QMenu *rmbMenu = new QMenu(this);
0417         rmbMenu->setTitle(m_estate->name());
0418 
0419         if (m_estate->isOwnedBySelf())
0420         {
0421             Player *player = m_estate->owner();
0422 
0423             // Mortgage toggle
0424             if (m_estate->isMortgaged())
0425             {
0426                 QAction *act = rmbMenu->addAction(i18n("Unmortgage"), this, SLOT(slotToggleMortgage()));
0427                 if (!m_estate->canToggleMortgage() || player->hasDebt())
0428                     act->setEnabled(false);
0429             }
0430             else
0431             {
0432                 QAction *act = rmbMenu->addAction(i18n("Mortgage"), this, SLOT(slotToggleMortgage()));
0433                 if (!m_estate->canToggleMortgage())
0434                     act->setEnabled(false);
0435             }
0436 
0437             QAction *act = nullptr;
0438             // Estate construction
0439             if (m_estate->houses()>=4)
0440                 act = rmbMenu->addAction(i18n("Build Hotel"), this, SLOT(slotHouseBuy()));
0441             else
0442                 act = rmbMenu->addAction(i18n("Build House"), this, SLOT(slotHouseBuy()));
0443 
0444             if (!m_estate->canBuyHouses() || player->hasDebt())
0445                 act->setEnabled(false);
0446 
0447             // Estate destruction
0448             if (m_estate->houses()==5)
0449                 act = rmbMenu->addAction(i18n("Sell Hotel"), this, SLOT(slotHouseSell()));
0450             else
0451                 act = rmbMenu->addAction(i18n("Sell House"), this, SLOT(slotHouseSell()));
0452 
0453             if (!(m_estate->canSellHouses()))
0454                 act->setEnabled(false);
0455 
0456             // Estate sell
0457             act = rmbMenu->addAction(i18n("Sell"), this, SLOT(slotSell()));
0458             if (!m_allowEstateSales)
0459                 act->setEnabled(false);
0460         }
0461         else
0462         {
0463             // Request trade
0464             if (Player *player = m_estate->owner())
0465                 rmbMenu->addAction(i18n("Request Trade with %1", player->name()), this, SLOT(slotNewTrade()));
0466         }
0467 
0468         rmbMenu->exec(e->globalPos());
0469         delete rmbMenu;
0470     }
0471 }
0472 
0473 void EstateView::mousePressEvent(QMouseEvent *e)
0474 {
0475     if (e->button()==Qt::LeftButton)
0476         Q_EMIT LMBClicked(m_estate);
0477 }
0478 
0479 void EstateView::slotToggleMortgage()
0480 {
0481     Q_EMIT estateToggleMortgage(m_estate);
0482 }
0483 
0484 void EstateView::slotHouseBuy()
0485 {
0486     Q_EMIT estateHouseBuy(m_estate);
0487 }
0488 
0489 void EstateView::slotHouseSell()
0490 {
0491     Q_EMIT estateHouseSell(m_estate);
0492 }
0493 
0494 void EstateView::slotSell()
0495 {
0496     Q_EMIT estateSell(m_estate);
0497 }
0498 
0499 void EstateView::slotNewTrade()
0500 {
0501     Q_EMIT newTrade(m_estate->owner());
0502 }
0503 
0504 // Kudos to Gallium <gallium@kde.org> for writing the Quartz KWin style and
0505 // letting me use the ultra slick algorithm!
0506 void EstateView::drawQuartzBlocks(QPixmap *pi, const QColor &c1, const QColor &c2)
0507 {
0508     QPainter px;
0509 
0510     if (pi==nullptr || pi->isNull())
0511         return;
0512 
0513     px.begin(pi);
0514 
0515     QLinearGradient gradient(0, 0, pi->width(), 0);
0516     gradient.setColorAt(0, c1);
0517     gradient.setColorAt(1, c2);
0518     px.fillRect(pi->rect(), gradient);
0519 
0520     px.fillRect( 2, 1, 3, 3, c1.lighter(120) );
0521     px.fillRect( 2, 5, 3, 3, c1 );
0522     px.fillRect( 2, 9, 3, 3, c1.lighter(110) );
0523     px.fillRect( 2, 13, 3, 3, c1 );
0524 
0525     px.fillRect( 6, 1, 3, 3, c1.lighter(110) );
0526     px.fillRect( 6, 5, 3, 3, c2.lighter(110) );
0527     px.fillRect( 6, 9, 3, 3, c1.lighter(120) );
0528     px.fillRect( 6, 13, 3, 3, c2.lighter(130) );
0529 
0530     px.fillRect( 10, 5, 3, 3, c1.lighter(110) );
0531     px.fillRect( 10, 9, 3, 3, c2.lighter(120) );
0532     px.fillRect( 10, 13, 3, 3, c2.lighter(150) );
0533 
0534     px.fillRect( 14, 1, 3, 3, c1.darker(110) );
0535     px.fillRect( 14, 9, 3, 3, c2.lighter(120) );
0536     px.fillRect( 14, 13, 3, 3, c1.darker(120) );
0537 
0538     px.fillRect( 18, 5, 3, 3, c1.lighter(110) );
0539     px.fillRect( 18, 13, 3, 3, c1.darker(110) );
0540 
0541     px.fillRect( 22, 9, 3, 3, c2.lighter(120));
0542     px.fillRect( 22, 13, 3, 3, c2.lighter(110) );
0543 }
0544 
0545 #include "moc_estateview.cpp"