1 /***************************************************************************
2 * Copyright (C) 2007 by Pierre Marchand *
3 * pierre@oep-h.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20 #include "fmpreviewlist.h"
21
22 #include "typotek.h"
23 #include "fontitem.h"
24 #include "mainviewwidget.h"
25 #include "fmfloatingpreview.h"
26 #include "fmfontdb.h"
27
28 #include <QImage>
29 #include <QDebug>
30 #include <QSettings>
31 #include <QScrollBar>
32 //#include <QDrag>
33 //#include <QMimeData>
34 #include <QApplication>
35 #include <QLabel>
36 #include <QPainter>
37 #include <QBrush>
38
39 #define FM_MINIMUM_PREVIEW_WIDTH 280
40
41 bool FMPreviewIconEngine::initState = false;
42 QPen FMPreviewIconEngine::pen = QPen();
43 QVector<QRgb> FMPreviewIconEngine::m_selPalette;
44 QRgb FMPreviewIconEngine::activatedColor = qRgb (9,223,11);
45 QRgb FMPreviewIconEngine::deactivatedColor = qRgb (190,190,190);
46 QRgb FMPreviewIconEngine::partlyActivatedColor = qRgb (166,220,220);
47
48
FMPreviewIconEngine()49 FMPreviewIconEngine::FMPreviewIconEngine()
50 :QIconEngine(),
51 activatedFont(NotActivated)
52 {
53 if(!initState)
54 {
55 // setup palette
56 QColor sColor( QApplication::palette().color(QPalette::Highlight) );
57 QColor tColor( QApplication::palette().color(QPalette::HighlightedText) );
58 m_selPalette.clear();
59 int sr(sColor.red());
60 int sg(sColor.green());
61 int sb(sColor.blue());
62 int tr(tColor.red());
63 int tg(tColor.green());
64 int tb(tColor.blue());
65 int cpal(256);
66 for ( int aa = 0; aa < cpal ; ++aa )
67 {
68 int sn(cpal - aa);
69 int tn(aa);
70 m_selPalette << qRgb (((sr*sn) + (tr*tn)) /cpal,
71 ((sg*sn) + (tg*tn)) /cpal,
72 ((sb*sn) + (tb*tn)) /cpal );
73 }
74
75 // setup "writing" pen
76 // pen.setColor(QColor(m_selPalette.at(128)));
77 pen.setColor(QColor(220,220,220));
78 pen.setWidth(1);
79
80 initState = true;
81 }
82
83 }
84
clone() const85 QIconEngine *FMPreviewIconEngine::clone() const
86 {
87 // TODO Implement this function
88 return 0;
89 }
90
actualSelPalette(const QVector<QRgb> & orig)91 QVector<QRgb> FMPreviewIconEngine::actualSelPalette(const QVector<QRgb>& orig)
92 {
93 QRgb r(QApplication::palette().color(QPalette::Highlight).rgb());
94 QVector<QRgb> ret;
95 for(int i(0); i<256; ++i)
96 ret << r;
97 QColor bgColor(QApplication::palette().color(QPalette::Base));
98 QColor fgColor(QApplication::palette().color(QPalette::Text));
99
100 // In m_selPalette, background is at the begining of the vector
101
102 bool DarkOnLight(fgColor.rgb() < bgColor.rgb());
103 // order is dark first, light last
104 QMap<QRgb, int> order;
105 for(int i(0); i < orig.count(); ++i)
106 order[orig[i]] = i;
107 QList<int> oIdx(order.values());
108 if(DarkOnLight)
109 {
110 // oIdx has background values at the end
111 int v(0);
112 for(int c(oIdx.count() - 1); c >= 0 ; --c)
113 {
114 ret [oIdx[c]] = m_selPalette[v];
115 ++v;
116 }
117 }
118 else
119 {
120 int v(0);
121 for(int c(0); c < oIdx.count() ; c++)
122 {
123 ret [oIdx[c]] = m_selPalette[v];
124 ++v;
125 }
126 }
127 return ret;
128 }
129
130
~FMPreviewIconEngine()131 FMPreviewIconEngine::~FMPreviewIconEngine()
132 {
133 // if(m_p)
134 // delete m_p;
135 }
136
paint(QPainter * painter,const QRect & rect,QIcon::Mode mode,QIcon::State state)137 void FMPreviewIconEngine::paint ( QPainter * painter, const QRect & rect, QIcon::Mode mode, QIcon::State state )
138 {
139 if(!m_p.isNull())
140 {
141 painter->save();
142 painter->translate(rect.x(),rect.y());
143 QRect r(0 , 0 , rect.width(), rect.height());
144 QPainterPath pp;
145 double rr(double(r.height()) / 5.0);
146 pp.addRoundedRect(r,rr,rr);
147 painter->setRenderHint(QPainter::Antialiasing, true);
148 // draw background
149 painter->save();
150 painter->setPen(Qt::NoPen);
151 if(mode == QIcon::Selected)
152 painter->setBrush(QApplication::palette().color(QPalette::Highlight));
153 else
154 painter->setBrush(QApplication::palette().color(QPalette::Base));
155 painter->drawPath(pp);
156 painter->restore();
157 // end of bg
158 painter->setPen(pen);
159 QRect tr(r);
160 tr.translate(0, (r.height() - m_p.height()) / 2);
161 if(mode == QIcon::Selected)
162 {
163 QImage hm(m_p.toImage().convertToFormat(QImage::Format_Indexed8));
164 hm.setColorTable(actualSelPalette(hm.colorTable()));
165 painter->setClipPath(pp);
166 painter->drawPixmap(tr, QPixmap::fromImage(hm) , r);
167 painter->drawPath(pp);
168 }
169 else
170 {
171 painter->drawPixmap(tr, m_p , r);
172 painter->drawPath(pp);
173
174 }
175 if(activatedFont != NotActivated)
176 {
177 painter->setPen(Qt::NoPen);
178 QPainterPath activationPath;
179 double rr2(rr/2.0);
180 activationPath.moveTo(rr, 0);
181 activationPath.cubicTo(rr2,0,
182 0,rr2,
183 0,rr);
184 activationPath.lineTo(0,rect.height() - rr);
185 activationPath.cubicTo(0,rect.height() -rr2,
186 rr2,rect.height(),
187 rr,rect.height());
188 activationPath.closeSubpath();
189 if(activatedFont == Activated)
190 painter->setBrush(QBrush(activatedColor));
191 else if(activatedFont == PartlyActivated)
192 painter->setBrush(QBrush(partlyActivatedColor));
193 painter->drawPath(activationPath);
194 }
195 painter->restore();
196 }
197 }
198
addPixmap(const QPixmap & pixmap,QIcon::Mode mode,QIcon::State state)199 void FMPreviewIconEngine::addPixmap ( const QPixmap & pixmap, QIcon::Mode mode, QIcon::State state )
200 {
201 m_p = pixmap;
202 }
203
204
FMPreviewModel(QObject * pa,FMPreviewView * wPa,QList<FontItem * > db)205 FMPreviewModel::FMPreviewModel( QObject * pa , FMPreviewView * wPa, QList<FontItem*> db )
206 : QAbstractListModel(pa) , m_view(wPa), base(db)
207 {
208 familyMode = false;
209 QSettings settings;
210 styleTooltipName = settings.value("Preview/StyleTooltipName","font-weight:bold;").toString();
211 styleTooltipPath = settings.value("Preview/StyleTooltipPath","font-weight:normal;font-size:small;").toString();
212 styleTooltipTags = settings.value("Preview/StyleTooltipTags","text-align:right;font-weight:normal;font-size:small;font-style:italic;").toString();
213
214 settings.setValue("Preview/StyleTooltipName", styleTooltipName);
215 settings.setValue("Preview/StyleTooltipPath", styleTooltipPath);
216 settings.setValue("Preview/StyleTooltipTags", styleTooltipTags);
217 }
218
data(const QModelIndex & index,int role) const219 QVariant FMPreviewModel::data(const QModelIndex & index, int role) const
220 {
221 if(!index.isValid())
222 return QVariant();
223
224 int row = index.row();
225 // qDebug()<<"D"<<row;
226 FontItem *fit;
227 if(base.isEmpty())
228 fit = FMFontDb::DB()->getFilteredFonts(true).at(row);
229 else
230 fit = base.at(row);
231 if(!fit)
232 return QVariant();
233
234 QColor bgColor(QApplication::palette().color(QPalette::Base));
235 QColor fgColor(QApplication::palette().color(QPalette::Text));
236
237 int width(m_view->getUsedWidth());
238
239 if(role == Qt::DisplayRole)
240 {
241 if( typotek::getInstance()->getPreviewSubtitled() )
242 return fit->fancyName() ;
243 else
244 return QVariant();
245 }
246 else if(role == Qt::DecorationRole)
247 {
248 QString word;
249 if(specString.isEmpty())
250 word = typotek::getInstance()->word(fit);
251 else
252 word = typotek::getInstance()->word(fit, specString);
253 QPixmap im(fit->oneLinePreviewPixmap(word,fgColor, bgColor, width ) );
254 FMPreviewIconEngine * pie(new FMPreviewIconEngine);
255 if(!familyMode)
256 pie->setActivation(fit->isActivated() ? FMPreviewIconEngine::Activated : FMPreviewIconEngine::NotActivated);
257 else
258 {
259 bool hasActive(false);
260 bool hasNotActive(false);
261 foreach(FontItem * f, FMFontDb::DB()->FamilySet(fit->family()))
262 {
263 if(f->isActivated())
264 hasActive = true;
265 else
266 hasNotActive = true;
267 if(hasActive && hasNotActive)
268 break;
269 }
270 if(hasNotActive && hasActive)
271 pie->setActivation(FMPreviewIconEngine::PartlyActivated);
272 else
273 {
274 pie->setActivation(hasActive ? FMPreviewIconEngine::Activated : FMPreviewIconEngine::NotActivated);
275 }
276 }
277 QIcon ic( pie );
278 ic.addPixmap(im);
279
280 return ic;
281 }
282 else if(role == Qt::ToolTipRole)
283 {
284 if(familyMode)
285 {
286 QList<FontItem*> fam(FMFontDb::DB()->FamilySet(fit->family()));
287 QString sRet;
288 sRet+= "<div style=\"" + styleTooltipName + "\">" + fit->family() + " ("+QString::number(fam.count())+")</div>";
289 sRet+= "<div style=\"" + styleTooltipTags + "\">" + fit->tags().join(QString(", ")) + "</div>";
290
291 foreach(FontItem* ffi, fam)
292 {
293 sRet += "<div style=\"" + styleTooltipPath + "\">" + ffi->variant() + "</div>";
294 }
295 return sRet;
296 }
297 if(typotek::getInstance()->getPreviewSubtitled())
298 {
299 return QString("<div style=\"" + styleTooltipPath + "\">" + fit->path() + "</div>");
300 }
301 else
302 {
303 QString complete;
304 complete += "<div style=\"" + styleTooltipName + "\">" + fit->fancyName() + "</div>";
305 complete += "\n";
306 complete += "<div style=\"" + styleTooltipPath + "\">" + fit->path() + "</div>";
307 return complete;
308 }
309 }
310 else if(role == PathRole)
311 {
312 return fit->path();
313 }
314
315 // fall back
316 return QVariant();
317
318 }
319
flags(const QModelIndex & index) const320 Qt::ItemFlags FMPreviewModel::flags(const QModelIndex & index) const
321 {
322 return (Qt::ItemIsEnabled | Qt::ItemIsSelectable);
323 }
324
rowCount(const QModelIndex & parent) const325 int FMPreviewModel::rowCount(const QModelIndex & parent) const
326 {
327 if(parent.isValid() || !typotek::getInstance()->getTheMainView())
328 return 0;
329 int cl(0);
330 if(base.isEmpty())
331 cl = FMFontDb::DB()->getFilteredFonts(true).count();
332 else
333 cl = base.count();
334 return cl;
335 }
336
dataChanged()337 void FMPreviewModel::dataChanged()
338 {
339 QAbstractItemModel::dataChanged(index(0),index(rowCount(QModelIndex()) - 1));
340 m_view->updateLayout();
341 emit layoutChanged ();
342 }
343
resetBase(QList<FontItem * > db)344 void FMPreviewModel::resetBase(QList<FontItem *>db)
345 {
346 base = db;
347 dataChanged();
348 }
349
getBase()350 QList<FontItem *> FMPreviewModel::getBase()
351 {
352 if(base.isEmpty())
353 return FMFontDb::DB()->getFilteredFonts(true);
354 else
355 return base;
356 }
357
358
FMPreviewView(QWidget * parent)359 FMPreviewView::FMPreviewView(QWidget * parent):
360 QListView(parent),
361 columns(1)
362 {
363 dragFlag = false;
364 setDragEnabled(true);
365 setDragDropMode(QAbstractItemView::DragDrop);
366 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
367 setSelectionRectVisible(false);
368
369 }
370
moveTo(const QString & fname)371 bool FMPreviewView::moveTo(const QString &fname)
372 {
373 QList<FontItem*> fl(reinterpret_cast<FMPreviewModel*>(model())->getBase());
374
375 QString uname(fname.toUpper());
376 const int fl_count(fl.count());
377 int rFont(fl_count);
378 for(int i(0); i < fl_count ; ++i)
379 {
380 QString pname(fl[i]->fancyName().toUpper());
381 pname.truncate(uname.count());
382 if(uname == pname)
383 {
384 rFont = i;
385 break;
386 }
387 }
388
389 if(rFont != fl_count)
390 {
391 QAbstractListModel *mod(reinterpret_cast<QAbstractListModel*>(model()));
392 QModelIndex mi(mod->index(rFont));
393 if(mi.isValid())
394 {
395 selectionModel()->setCurrentIndex(mi, QItemSelectionModel::ClearAndSelect);
396 // scrollTo ( mi );
397 return true;
398 }
399 }
400
401 return false;
402 }
403
resizeEvent(QResizeEvent * event)404 void FMPreviewView::resizeEvent(QResizeEvent * event)
405 {
406 int actualWidth(width() - 20); // if we use the viewport size, it becomes funny when a resize shows/hides the scrollbar
407 setSpacing(0);
408 int gHeight(2.0 * typotek::getInstance()->getPreviewSize() * typotek::getInstance()->getDpiY() / 72.0);
409 qDebug()<< "VW" << actualWidth<<verticalScrollBar()->width()<< "S" <<spacing();
410 double cNr(1);
411
412 if(columns == 1)
413 usedWidth = qRound((double(actualWidth) / columns));
414 else
415 {
416 int minCellWidth(FM_MINIMUM_PREVIEW_WIDTH + 6);
417 cNr = qRound(double(actualWidth) / minCellWidth);
418 minCellWidth = qRound((double(actualWidth) / cNr) - 6);
419 qDebug()<< "C" << cNr << "U" << minCellWidth ;
420 setGridSize(QSize(minCellWidth, gHeight + 12));
421 usedWidth = minCellWidth - 6;
422 }
423 setIconSize(QSize(usedWidth, gHeight + 6));
424 QListView::resizeEvent(event);
425 }
426
mousePressEvent(QMouseEvent * event)427 void FMPreviewView::mousePressEvent(QMouseEvent * event)
428 {
429 if (event->button() == Qt::LeftButton)
430 {
431 startDragPoint = event->pos();
432 dragFlag = false;
433 // const QModelIndex idx ( indexAt(startDragPoint) );
434 // if(idx.isValid())
435 // emit pressed(idx);
436 }
437 QListView::mousePressEvent(event);
438 }
439
mouseMoveEvent(QMouseEvent * event)440 void FMPreviewView::mouseMoveEvent(QMouseEvent * event)
441 {
442 if(!(event->modifiers().testFlag( Qt::ControlModifier )))
443 return;
444 if (!(event->buttons() & Qt::LeftButton))
445 return;
446 if ((event->pos() - startDragPoint).manhattanLength() < QApplication::startDragDistance())
447 return;
448
449 FMPreviewModel * m(reinterpret_cast<FMPreviewModel*>(model()));
450 if(m && m->getFamilyMode())
451 return;
452 // Create a window with the current preview
453 if(currentIndex().isValid() && (!dragFlag))
454 {
455 dragFlag = true;
456 // FontItem * sf(typotek::getInstance()->getSelectedFont());
457 QModelIndex idx = indexAt(startDragPoint);
458 QString fname = idx.data(FMPreviewModel::PathRole).toString();
459 if(!fname.isEmpty())
460 {
461 FontItem * sf(FMFontDb::DB()->Font(fname));
462 if(sf)
463 FMFloatingPreview::create(sf, QRect(event->globalPos(), QSize(width() ,1) ));
464 }
465 }
466
467 }
468
keyPressEvent(QKeyEvent * event)469 void FMPreviewView::keyPressEvent(QKeyEvent *event)
470 {
471 qDebug()<<"FMPreviewView::keyPressEvent"<<event;
472 if((!event->text().isEmpty()) && (event->text().at(0).isLetterOrNumber()))
473 emit keyPressed(event->text());
474 else
475 QListView::keyPressEvent(event);
476 }
477
updateLayout()478 void FMPreviewView::updateLayout()
479 {
480 update();
481 }
482
setCurrentFont(const QString & name)483 void FMPreviewView::setCurrentFont(const QString & name)
484 {
485 QList<FontItem*> fl(reinterpret_cast<FMPreviewModel*>(model())->getBase());
486
487 const int fl_count(fl.count());
488 int rFont(fl_count);
489 for(int i(0); i < fl_count ; ++i)
490 {
491 if(fl[i]->path() == name)
492 {
493 rFont = i;
494 break;
495 }
496 }
497
498 if(rFont != fl_count)
499 {
500 QAbstractListModel *mod(reinterpret_cast<QAbstractListModel*>(model()));
501 QModelIndex mi(mod->index(rFont));
502 if(mi.isValid())
503 {
504 selectionModel()->setCurrentIndex(mi, QItemSelectionModel::ClearAndSelect);
505 // scrollTo ( mi );
506 }
507 }
508 }
509