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"