diff options
Diffstat (limited to 'kmahjongg/Preview.cpp')
-rw-r--r-- | kmahjongg/Preview.cpp | 513 |
1 files changed, 513 insertions, 0 deletions
diff --git a/kmahjongg/Preview.cpp b/kmahjongg/Preview.cpp new file mode 100644 index 00000000..edd8ef79 --- /dev/null +++ b/kmahjongg/Preview.cpp @@ -0,0 +1,513 @@ +#include <kapplication.h> +#include <kfiledialog.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kpushbutton.h> +#include <kstandarddirs.h> +#include <kstdguiitem.h> +#include <kimageio.h> + +#include <qcombobox.h> +#include <qhgroupbox.h> +#include <qimage.h> +#include <qregexp.h> +#include <qpainter.h> +#include <qvbox.h> + +#include "prefs.h" +#include "Preview.h" + +static const char * themeMagicV1_0= "kmahjongg-theme-v1.0"; + +Preview::Preview(QWidget* parent) : KDialogBase(parent), m_tiles(true) +{ + KPushButton *loadButton; + QGroupBox *group; + QVBox *page; + + page = new QVBox(this); + + group = new QHGroupBox(page); + + m_combo = new QComboBox(false, group); + connect(m_combo, SIGNAL(activated(int)), SLOT(selectionChanged(int))); + + loadButton = new KPushButton(i18n("Load..."), group); + connect( loadButton, SIGNAL(clicked()), SLOT(load()) ); + + m_drawFrame = new FrameImage(page); + m_drawFrame->setFixedSize(310, 236); + + m_changed = false; + + setMainWidget(page); + setFixedSize(sizeHint()); +} + +Preview::~Preview() +{ +} + +void Preview::selectionChanged(int which) +{ + m_selectedFile = m_fileList[which]; + drawPreview(); + m_drawFrame->repaint(0,0,-1,-1,false); + markChanged(); +} + +bool Preview::isChanged() +{ + return m_changed; +} + +void Preview::markChanged() +{ + m_changed = true; +} + +void Preview::markUnchanged() +{ + m_changed = false; +} + +void Preview::initialise(const PreviewType type) +{ + QString extension; + QString tile = Prefs::tileSet(); + QString back = Prefs::background(); + QString layout = Prefs::layout(); + + // set up the concept of the current file. Initialised to the preferences + // value initially. Set the caption to indicate what we are doing + switch (type) + { + case background: + setCaption(i18n("Change Background Image")); + m_selectedFile = back; + m_fileSelector = i18n("*.bgnd|Background Image (*.bgnd)\n"); + m_fileSelector += KImageIO::pattern()+"\n"; + extension = "*.bgnd"; + break; + + case tileset: + setCaption(i18n("Change Tile Set")); + m_fileSelector = i18n("*.tileset|Tile Set File (*.tileset)\n"); + m_selectedFile = tile; + extension = "*.tileset"; + break; + + case board: + m_fileSelector = i18n("*.layout|Board Layout File (*.layout)\n"); + setCaption(i18n("Change Board Layout")); + m_selectedFile = layout; + extension = "*.layout"; + break; + + case theme: + m_fileSelector = i18n("*.theme|KMahjongg Theme File (*.theme)\n"); + setCaption(i18n("Choose Theme")); + m_selectedFile=""; + extension = "*.theme"; + + m_themeLayout=""; + m_themeBack=""; + m_themeTileset=""; + + default: + break; + } + + m_fileSelector += i18n("*|All Files"); + enableButtonApply(type != board); + + m_previewType = type; + // we start with no change indicated + markUnchanged(); + + m_fileList = kapp->dirs()->findAllResources("appdata", "pics/*"+extension, false, true); + + // get rid of files from the last invocation + m_combo->clear(); + + QStringList names; + QStringList::const_iterator it, itEnd; + it = m_fileList.begin(); + itEnd = m_fileList.end(); + for ( ; it != itEnd; ++it) + { + QFileInfo fi(*it); + names << fi.baseName(); + } + + m_combo->insertStringList(names); + m_combo->setEnabled(m_fileList.count()); + drawPreview(); +} + +void Preview::slotApply() { + if (isChanged()) { + applyChange(); + markUnchanged(); + } +} + +void Preview::slotOk() { + slotApply(); + accept(); +} + +void Preview::load() { + KURL url = KFileDialog::getOpenURL(QString::null, m_fileSelector, this, i18n("Open Board Layout" )); + if ( !url.isEmpty() ) { + m_selectedFile = url.path(); + drawPreview(); + m_drawFrame->repaint(0,0,-1,-1,false); + markChanged(); + } +} + +// Top level preview drawing method. Background, tileset and layout +// are initialised from the preferences. Depending on the type +// of preview dialog we pick up the selected file for one of these +// chaps. + +void Preview::drawPreview() +{ + QString tile = Prefs::tileSet(); + QString back = Prefs::background(); + QString layout = Prefs::layout(); + + switch (m_previewType) + { + case background: + back = m_selectedFile; + break; + + case tileset: + tile = m_selectedFile; + break; + + case board: + layout = m_selectedFile; + break; + + case theme: + // a theme is quite a bit of work. We load the + // specified bits in (layout, background and tileset + if (!m_selectedFile.isEmpty()) + { + QString backRaw, layoutRaw, tilesetRaw, magic; + + QFile in(m_selectedFile); + if (in.open(IO_ReadOnly)) + { + QTextStream stream(&in); + magic = stream.readLine(); + if (magic != themeMagicV1_0) + { + in.close(); + KMessageBox::sorry(this, i18n("That is not a valid theme file.")); + break; + } + tilesetRaw = stream.readLine(); + backRaw = stream.readLine(); + layoutRaw = stream.readLine(); + in.close(); + + tile = tilesetRaw; + tile.replace(":", "/kmahjongg/pics/"); + if (!QFile::exists(tile)) + { + tile = tilesetRaw; + tile = "pics/" + tile.right(tile.length() - tile.find(":") - 1 ); + tile = locate("appdata", tile); + } + + back = backRaw; + back.replace(":", "/kmahjongg/pics/"); + if (!QFile::exists(back)) + { + back = backRaw; + back = "pics/" + back.right(back.length() - back.find(":") - 1); + back = locate("appdata", back); + } + + layout = layoutRaw; + layout.replace(":", "/kmahjongg/pics/"); + if (!QFile::exists(layout)) + { + layout = layoutRaw; + layout = "pics/" + layout.right(layout.length() - layout.find(":") - 1); + layout = locate("appdata", layout); + } + + m_themeBack=back; + m_themeLayout=layout; + m_themeTileset=tile; + } + } + break; + } + + renderBackground(back); + renderTiles(tile, layout); +} + +void Preview::paintEvent( QPaintEvent* ){ + m_drawFrame->repaint(false); +} + +// the user selected ok, or apply. This method passes the changes +// across to the game widget and if necessary forces a board redraw +// (unnecessary on layout changes since it only effects the next game) +void Preview::applyChange() +{ + switch (m_previewType) + { + case background: + loadBackground(m_selectedFile, false); + break; + + case tileset: + loadTileset(m_selectedFile); + break; + + case board: + loadBoard(m_selectedFile); + break; + + case theme: + if (!m_themeLayout.isEmpty() && !m_themeBack.isEmpty() && !m_themeTileset.isEmpty()) + { + loadBackground(m_themeBack, false); + loadTileset(m_themeTileset); + loadBoard(m_themeLayout); + } + break; + } + + // don't redraw for a layout change + if (m_previewType == board || m_previewType == theme) layoutChange(); + else boardRedraw(true); + + // either way we mark the current value as unchanged + markUnchanged(); +} + +// Render the background to the pixmap. +void Preview::renderBackground(const QString &bg) { + QImage img; + QImage tmp; + QPixmap *p; + QPixmap *b; + p = m_drawFrame->getPreviewPixmap(); + m_back.load(bg, p->width(), p->height()); + b = m_back.getBackground(); + bitBlt( p, 0,0, + b,0,0, b->width(), b->height(), CopyROP ); +} + +// This method draws a mini-tiled board with no tiles missing. + +void Preview::renderTiles(const QString &file, const QString &layout) { + m_tiles.loadTileset(file, true); + m_boardLayout.loadBoardLayout(layout); + + QPixmap *dest = m_drawFrame->getPreviewPixmap(); + int xOffset = m_tiles.width()/2; + int yOffset = m_tiles.height()/2; + short tile = 0; + + // we iterate over the depth stacking order. Each successive level is + // drawn one indent up and to the right. The indent is the width + // of the 3d relief on the tile left (tile shadow width) + for (int z=0; z<BoardLayout::depth; z++) { + // we draw down the board so the tile below over rights our border + for (int y = 0; y < BoardLayout::height; y++) { + // drawing right to left to prevent border overwrite + for (int x=BoardLayout::width-1; x>=0; x--) { + int sx = x*(m_tiles.qWidth() )+xOffset; + int sy = y*(m_tiles.qHeight() )+yOffset; + if (m_boardLayout.getBoardData(z, y, x) != '1') { + continue; + } + QPixmap *t = m_tiles.unselectedPixmaps(tile); + + // Only one compilcation. Since we render top to bottom , left + // to right situations arise where...: + // there exists a tile one q height above and to the left + // in this situation we would draw our top left border over it + // we simply split the tile draw so the top half is drawn + // minus border + + if ((x>1) && (y>0) && m_boardLayout.getBoardData(z,y-1,x-2)=='1'){ + bitBlt( dest, sx+2, sy, + t, 2,0, t->width(), t->height()/2, CopyROP ); + bitBlt( dest, sx, sy+t->height()/2, + t, 0,t->height()/2,t->width(),t->height()/2,CopyROP); + } else { + + bitBlt( dest, sx, sy, + t, 0,0, t->width(), t->height(), CopyROP ); + } + tile++; + if (tile == 35) + tile++; + tile = tile % 43; + } + } + xOffset +=m_tiles.shadowSize(); + yOffset -=m_tiles.shadowSize(); + } +} + +// this really does not belong here. It will be fixed in v1.1 onwards +void Preview::saveTheme() { + QString tile = Prefs::tileSet(); + QString back = Prefs::background(); + QString layout = Prefs::layout(); + + QString with = ":"; + // we want to replace any path in the default store + // with a + + QRegExp p(locate("data_dir", "/kmahjongg/pics/")); + + back.replace(p,with); + tile.replace(p,with); + layout.replace(p,with); + + + // Get the name of the file to save + KURL url = KFileDialog::getSaveURL( + NULL, + "*.theme", + parentWidget(), + i18n("Save Theme" )); + if ( url.isEmpty() ) + return; + + if( !url.isLocalFile() ) + { + KMessageBox::sorry( this, i18n( "Only saving to local files currently supported." ) ); + return; + } + + // Are we over writing an existin file, or was a directory selected? + QFileInfo f( url.path() ); + if( f.isDir() ) + return; + if (f.exists()) { + // if it already exists, querie the user for replacement + int res=KMessageBox::warningContinueCancel(this, + i18n("A file with that name " + "already exists. Do you " + "wish to overwrite it?"),QString::null,i18n("Overwrite")); + if (res != KMessageBox::Continue) + return ; + } + FILE *outFile = fopen( QFile::encodeName(url.path()), "w" ); + if (outFile == NULL) { + KMessageBox::sorry(this, + i18n("Could not write to file. Aborting.")); + return; + } + + fprintf(outFile,"%s\n%s\n%s\n%s\n", + themeMagicV1_0, + tile.utf8().data(), + back.utf8().data(), + layout.utf8().data()); + fclose(outFile); +} + +FrameImage::FrameImage (QWidget *parent, const char *name) + : QFrame(parent, name) +{ + rx = -1; + thePixmap = new QPixmap(); +} + +FrameImage::~FrameImage() +{ + delete thePixmap; +} + +void FrameImage::setGeometry(int x, int y, int w, int h) { + QFrame::setGeometry(x,y,w,h); + + thePixmap->resize(size()); + +} + +void FrameImage::paintEvent( QPaintEvent* pa ) +{ + QFrame::paintEvent(pa); + + QPainter p(this); + + + QPen line; + line.setStyle(DotLine); + line.setWidth(2); + line.setColor(yellow); + p.setPen(line); + p.setBackgroundMode(OpaqueMode); + p.setBackgroundColor(black); + + int x = pa->rect().left(); + int y = pa->rect().top(); + int h = pa->rect().height(); + int w = pa->rect().width(); + + p.drawPixmap(x+frameWidth(),y+frameWidth(),*thePixmap,x+frameWidth(),y+frameWidth(),w-(2*frameWidth()),h-(2*frameWidth())); + if (rx >=0) { + + p.drawRect(rx, ry, rw, rh); + p.drawRect(rx+rs, ry, rw-rs, rh-rs); + p.drawLine(rx, ry+rh, rx+rs, ry+rh-rs); + + int midX = rx+rs+((rw-rs)/2); + int midY = ry+((rh-rs)/2); + switch (rt) { + case 0: // delete mode cursor + p.drawLine(rx+rs, ry, rx+rw, ry+rh-rs); + p.drawLine(rx+rw, ry, rx+rs, ry+rh-rs); + break; + case 1: // insert cursor + p.drawLine(midX, ry, midX, ry+rh-rs); + p.drawLine(rx+rs, midY, rx+rw, midY); + break; + case 2: // move mode cursor + p.drawLine(midX, ry, rx+rw, midY); + p.drawLine(rx+rw, midY, midX, ry+rh-rs); + p.drawLine(midX, ry+rh-rs, rx+rs, midY); + p.drawLine(rx+rs, midY, midX, ry); + + break; + } + + } +} + +void FrameImage::setRect(int x,int y,int w,int h, int s, int t) +{ + rx = x; + ry = y; + rw = w; + rh = h; + rt = t; + rs = s; +} + +// Pass on the mouse presed event to our owner + +void FrameImage::mousePressEvent(QMouseEvent *m) { + mousePressed(m); +} + +void FrameImage::mouseMoveEvent(QMouseEvent *e) { + mouseMoved(e); +} + +#include "Preview.moc" |