1 /***************************************************************************
2  *   Copyright (C) 2010 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 
21 #include "samplewidget.h"
22 #include "sampletoolbar.h"
23 #include "ui_samplewidget.h"
24 #include "typotek.h"
25 #include "fmbaseshaper.h"
26 #include "fmfontdb.h"
27 #include "fontitem.h"
28 #include "fmlayout.h"
29 #include "textprogression.h"
30 #include "opentypetags.h"
31 
32 #include <QApplication>
33 #include <QMap>
34 #include <QTreeWidgetItem>
35 #include <QSettings>
36 #include <QPrintDialog>
37 #include <QPrinter>
38 #include <QFileSystemWatcher>
39 #include <QDebug>
40 #include <QTimer>
41 #include <QDataStream>
42 #include <QSettings>
43 #include <QStyledItemDelegate>
44 #include <QKeyEvent>
45 #include <QDateTime>
46 
47 
toByteArray() const48 QByteArray SampleWidget::State::toByteArray() const
49 {
50 	QByteArray b;
51 	QDataStream ds(&b, QIODevice::WriteOnly);
52 	ds << sampleName;
53 	ds << fontSize;
54 	ds << renderHinting;
55 	ds << shaper;
56 	ds << script;
57 	return b;
58 }
59 
60 
setLayout(FMLayout * l,const QList<GlyphList> & spec,double fs,FontItem * f,unsigned int hinting)61 void FMLayoutThread::setLayout(FMLayout * l, const QList<GlyphList>& spec , double fs, FontItem* f, unsigned int hinting)
62 {
63 	pLayout = l;
64 	pLayout->setContext(false);
65 	gl = spec;
66 	fontSize = fs;
67 	font = f;
68 	fHinting = hinting;
69 }
70 
run()71 void FMLayoutThread::run()
72 {
73 	FontItem * tf(new FontItem(font->path(),font->family(),font->variant(),font->type(), font->isActivated()));
74 	tf->setFTHintMode(fHinting);
75 	pLayout->doLayout(gl, fontSize, tf);
76 	delete tf;
77 }
78 
fromByteArray(QByteArray b)79 SampleWidget::State SampleWidget::State::fromByteArray(QByteArray b)
80 {
81 	QDataStream ds(&b, QIODevice::ReadOnly);
82 	QString sn;
83 	double fs;
84 	unsigned int rh;
85 	QString sh;
86 	QString sc;
87 	ds >> sn;
88 	ds >> fs;
89 	ds >> rh;
90 	ds >> sh;
91 	ds >> sc;
92 //	State*  pState(new State(sn,fs,rh,sh,sc));
93 //	State rState(*pState);
94 	sampleName = sn;
95 	fontSize = fs;
96 	renderHinting = rh;
97 	shaper = sh;
98 	script = sc;
99 //	return State(sn,fs,rh,sh,sc);
100 	return *this;
101 }
102 
103 const QString SampleWidget::Name = QObject::tr("Sample");
104 
SampleWidget(const QString & fid,QWidget * parent)105 SampleWidget::SampleWidget(const QString& fid, QWidget *parent) :
106 		FloatingWidget(fid, Name, parent),
107 		ui(new Ui::SampleWidget),
108 		fontIdentifier(fid)
109 {
110 	layoutTimer = new QTimer(this);
111 	layoutWait = 1000;
112 	layoutForPrint = false;
113 	layoutSwitch = false;
114 	ui->setupUi(this);
115 //	ui->textProgression->setVisible(false);
116 
117 	sampleToolBar = new SampleToolBar(this);
118 	ui->sampleGridLayout->addWidget(sampleToolBar, 1,0, Qt::AlignRight | Qt::AlignBottom);
119 
120 
121 	sampleNameEditor = new QStyledItemDelegate(ui->sampleTextTree);
122 	ui->sampleTextTree->setItemDelegate(sampleNameEditor);
123 	refillSampleList();
124 	fillOTTree();
125 
126 #ifdef PLATFORM_APPLE
127       fileInfo.setFile(fid);
128       fileLastModified = fileInfo.lastModified().toMSecsSinceEpoch();
129 #endif
130 	sysWatcher = new QFileSystemWatcher(this);
131 	sysWatcher->addPath(fid);
132 	reloadTimer = new QTimer(this);
133 	reloadTimer->setInterval(1000);
134 
135 	loremScene = new QGraphicsScene;
136 	ftScene =  new QGraphicsScene;
137 	QRectF pageRect ( 0,0,597.6,842.4 ); //TODO find means to smartly decide of page size (here, iso A4)
138 
139 	loremScene->setSceneRect ( pageRect );
140 
141 	ftScene->setSceneRect ( 0,0, 597.6 * typotek::getInstance()->getDpiX() / 72.0, 842.4 * typotek::getInstance()->getDpiX() / 72.0);
142 	ui->loremView->setScene ( loremScene );
143 	ui->loremView->locker = false;
144 	double horiScaleT (typotek::getInstance()->getDpiX() / 72.0);
145 	double vertScaleT ( typotek::getInstance()->getDpiY() / 72.0);
146 	QTransform adjustAbsoluteViewT( horiScaleT , 0, 0,vertScaleT, 0, 0 );
147 	ui->loremView->setTransform ( adjustAbsoluteViewT , false );
148 
149 	ui->loremView_FT->setScene ( ftScene );
150 	ui->loremView_FT->locker = false;
151 	ui->loremView_FT->fakePage();
152 
153 	layoutThread = new  FMLayoutThread;
154 
155 	FontItem * cf(FMFontDb::DB()->Font(fid));
156 	textLayoutVect = new FMLayout(loremScene, cf);
157 	textLayoutFT =  new FMLayout(ftScene);
158 
159 
160 	QSettings settings;
161 	State s;
162 	s.fontSize = 14;
163 	QByteArray bs = settings.value("Sample/state", s.toByteArray()).toByteArray();
164 	setState(s.fromByteArray(bs));
165 	sampleRatio = 1.2;
166 	sampleInterSize = sampleFontSize * sampleRatio;
167 
168 	createConnections();
169 	slotView();
170 }
171 
~SampleWidget()172 SampleWidget::~SampleWidget()
173 {
174 	removeConnections();
175 	delete ui;
176 	delete loremScene;
177 	delete ftScene;
178 	delete textLayoutFT;
179 	delete textLayoutVect;
180 }
181 
createConnections()182 void SampleWidget::createConnections()
183 {
184 	// connections
185 
186 	connect ( ui->loremView, SIGNAL(pleaseUpdateMe()), this, SLOT(slotUpdateSView()));
187 	connect ( ui->loremView, SIGNAL(pleaseZoom(int)),this,SLOT(slotZoom(int)));
188 
189 	connect ( ui->loremView_FT, SIGNAL(pleaseZoom(int)),this,SLOT(slotZoom(int)));
190 	connect ( ui->loremView_FT, SIGNAL(pleaseUpdateMe()), this, SLOT(slotUpdateRView()));
191 
192 	connect ( textLayoutVect, SIGNAL(updateLayout()),this, SLOT(slotView()));
193 	connect ( this, SIGNAL(stopLayout()), textLayoutVect,SLOT(stopLayout()));
194 	connect ( textLayoutFT, SIGNAL(updateLayout()),this, SLOT(slotView()));
195 	connect ( this, SIGNAL(stopLayout()), textLayoutFT,SLOT(stopLayout()));
196 
197 	connect ( ui->sampleTextTree,SIGNAL ( itemSelectionChanged ()),this,SLOT ( slotSampleChanged() ) );
198 	connect ( ui->sampleTextTree,SIGNAL ( itemSelectionChanged ()),this,SLOT ( slotEditSample() ) );
199 	connect ( sampleToolBar, SIGNAL( SizeChanged(double) ),this,SLOT(slotLiveFontSize(double)));
200 
201 	connect ( ui->OpenTypeTree, SIGNAL ( itemClicked ( QTreeWidgetItem*, int ) ), this, SLOT ( slotFeatureChanged() ) );
202 	connect ( ui->saveDefOTFBut, SIGNAL(released()),this,SLOT(slotDefaultOTF()));
203 	connect ( ui->resetDefOTFBut, SIGNAL(released()),this,SLOT(slotResetOTF()));
204 
205 //	connect ( ui->textProgression, SIGNAL ( stateChanged (  ) ),this ,SLOT(slotProgressionChanged()));
206 
207 	connect(ui->toolbar, SIGNAL(Print()), this, SLOT(slotPrint()));
208 	connect(ui->toolbar, SIGNAL(Close()), this, SLOT(close()));
209 	connect(ui->toolbar, SIGNAL(Hide()), this, SLOT(hide()));
210 	connect(ui->toolbar, SIGNAL(Detach()), this, SLOT(ddetach()));
211 
212 	connect(sysWatcher, SIGNAL(fileChanged(QString)),this, SLOT(slotFileChanged(QString)));
213 	connect(reloadTimer,SIGNAL(timeout()), this, SLOT(slotReload()));
214 
215 	connect(this, SIGNAL(stateChanged()), this, SLOT(saveState()));
216 
217 	connect(sampleToolBar, SIGNAL(OpenTypeToggled(bool)), this, SLOT(slotShowOpenType(bool)));
218 	connect(sampleToolBar, SIGNAL(SampleToggled(bool)), this, SLOT(slotShowSamples(bool)));
219 	connect(sampleToolBar, SIGNAL(ScriptSelected()), this, SLOT(slotScriptChange()));
220 
221 	connect(ui->addSampleButton, SIGNAL(clicked()), this, SLOT(slotAddSample()));
222 	connect(ui->removeSampleButton, SIGNAL(clicked()), this, SLOT(slotRemoveSample()));
223 	connect(sampleNameEditor, SIGNAL(closeEditor(QWidget*)), this, SLOT(slotSampleNameEdited(QWidget*)));
224 	connect(ui->sampleEdit, SIGNAL(textChanged()), this, SLOT(slotUpdateSample()));
225 
226 
227 	connect(textLayoutFT, SIGNAL(clearScene()), this, SLOT(clearFTScene()));
228 }
229 
230 
removeConnections()231 void SampleWidget::removeConnections()
232 {
233 
234 	disconnect ( ui->loremView, SIGNAL(pleaseUpdateMe()), this, SLOT(slotUpdateSView()));
235 	disconnect ( ui->loremView, SIGNAL(pleaseZoom(int)),this,SLOT(slotZoom(int)));
236 
237 	disconnect ( ui->loremView_FT, SIGNAL(pleaseZoom(int)),this,SLOT(slotZoom(int)));
238 	disconnect ( ui->loremView_FT, SIGNAL(pleaseUpdateMe()), this, SLOT(slotUpdateRView()));
239 
240 	disconnect ( textLayoutVect, SIGNAL(updateLayout()),this, SLOT(slotView()));
241 	disconnect ( this, SIGNAL(stopLayout()), textLayoutVect,SLOT(stopLayout()));
242 	disconnect ( textLayoutFT, SIGNAL(updateLayout()),this, SLOT(slotView()));
243 	disconnect ( this, SIGNAL(stopLayout()), textLayoutFT,SLOT(stopLayout()));
244 
245 	disconnect ( ui->sampleTextTree,SIGNAL ( itemSelectionChanged ()),this,SLOT ( slotSampleChanged() ) );
246 	disconnect ( sampleToolBar, SIGNAL( SizeChanged(double) ),this,SLOT(slotLiveFontSize(double)));
247 
248 	disconnect ( ui->OpenTypeTree, SIGNAL ( itemClicked ( QTreeWidgetItem*, int ) ), this, SLOT ( slotFeatureChanged() ) );
249 	disconnect ( ui->saveDefOTFBut, SIGNAL(released()),this,SLOT(slotDefaultOTF()));
250 	disconnect ( ui->resetDefOTFBut, SIGNAL(released()),this,SLOT(slotResetOTF()));
251 
252 //	disconnect ( ui->textProgression, SIGNAL ( stateChanged (  ) ),this ,SLOT(slotProgressionChanged()));
253 
254 	disconnect(ui->toolbar, SIGNAL(Print()), this, SLOT(slotPrint()));
255 	disconnect(ui->toolbar, SIGNAL(Close()), this, SLOT(close()));
256 	disconnect(ui->toolbar, SIGNAL(Hide()), this, SLOT(hide()));
257 	disconnect(ui->toolbar, SIGNAL(Detach()), this, SLOT(ddetach()));
258 
259 	disconnect(sysWatcher, SIGNAL(fileChanged(QString)),this, SLOT(slotFileChanged(QString)));
260 
261 	disconnect(this, SIGNAL(stateChanged()), this, SLOT(saveState()));
262 }
263 
changeEvent(QEvent * e)264 void SampleWidget::changeEvent(QEvent *e)
265 {
266 	QWidget::changeEvent(e);
267 	switch (e->type()) {
268 	case QEvent::LanguageChange:
269 		ui->retranslateUi(this);
270 		break;
271 	default:
272 		break;
273 	}
274 }
275 
276 
textScene() const277 QGraphicsScene * SampleWidget::textScene() const
278 {
279 	return loremScene;
280 }
281 
state() const282 SampleWidget::State SampleWidget::state() const
283 {
284 	State ret;
285 	ret.set = true;
286 	ret.fontSize = sampleToolBar->getFontSize();
287 //	ret.renderRaster = ui->freetypeRadio->isChecked();
288 	ret.renderHinting = 0;
289 //	if(ui->normalHinting->isChecked())
290 //		ret.renderHinting = 1;
291 //	else if(ui->lightHinting->isChecked())
292 //		ret.renderHinting = 2;
293 	ret.sampleName = ui->sampleTextTree->currentItem()->data(0, Qt::UserRole).toString();
294 	if(ui->useShaperCheck->isChecked())
295 	{
296 		ret.script = ui->langCombo->currentText();
297 		ret.shaper = ui->shaperTypeCombo->currentText();
298 	}
299 	return ret;
300 }
301 
setState(const SampleWidget::State & s)302 void SampleWidget::setState(const SampleWidget::State &s)
303 {
304 	if(!s.set)
305 		return;
306 	sampleToolBar->setFontSize( s.fontSize );
307 	reSize( s.fontSize, s.fontSize * sampleRatio );
308 
309 //	{
310 //		switch(s.renderHinting)
311 //		{
312 //		case 0: ui->noHinting->setChecked(true);
313 //			break;
314 //		case 1: ui->normalHinting->setChecked(true);
315 //			break;
316 //		case 2: ui->lightHinting->setChecked(true);
317 //			break;
318 //		default:break;
319 //		}
320 //	}
321 
322 	QTreeWidgetItem * targetItem = 0;
323 	for(int i(0); i < ui->sampleTextTree->topLevelItemCount(); ++i)
324 	{
325 		QTreeWidgetItem * tli(ui->sampleTextTree->topLevelItem(i));
326 		for(int ii(0); ii < tli->childCount(); ++ii)
327 		{
328 			if(tli->child(ii)->data(0, Qt::UserRole).toString() == s.sampleName)
329 			{
330 				targetItem = tli->child(ii);
331 				typotek::getInstance()->namedSample(s.sampleName);
332 				break;
333 			}
334 		}
335 		if(targetItem != 0)
336 			break;
337 	}
338 //	qDebug()<<"TI"<<targetItem;
339 	if(targetItem != 0)
340 		ui->sampleTextTree->setCurrentItem(targetItem, 0, QItemSelectionModel::SelectCurrent);
341 
342 //	if(!s.shaper.isEmpty())
343 //	{
344 //		ui->useShaperCheck->setChecked(true);
345 //		ui->shaperTypeCombo->setCurrentIndex(ui->shaperTypeCombo->findText(s.shaper));
346 //		ui->langCombo->setCurrentIndex(ui->langCombo->findText(s.script));
347 //	}
348 
349 	slotView();
350 	slotEditSample();
351 }
352 
slotView()353 void SampleWidget::slotView()
354 {
355 	qDebug()<<"SampleWidget::slotView "<< fontIdentifier;
356 //	disconnect(textLayoutFT, SIGNAL(drawBaselineForMe(double)), this, SLOT(drawBaseline(double)));
357 	QTime t;
358 	t.start();
359 	FontItem *f(FMFontDb::DB()->Font( fontIdentifier ));
360 	if ( !f )
361 		return;
362 
363 	bool wantDeviceDependant = !layoutForPrint;
364 	if(wantDeviceDependant)
365 	{
366 		f->setFTHintMode(hinting());
367 	}
368 
369 //	if(ui->textProgression->inLine() == TextProgression::INLINE_LTR )
370 		f->setProgression(PROGRESSION_LTR );
371 //	else if(ui->textProgression->inLine() == TextProgression::INLINE_RTL )
372 //		f->setProgression(PROGRESSION_RTL);
373 //	else if(ui->textProgression->inLine() == TextProgression::INLINE_TTB )
374 //		f->setProgression(PROGRESSION_TTB );
375 //	else if(ui->textProgression->inLine() == TextProgression::INLINE_BTT )
376 //		f->setProgression(PROGRESSION_BTT);
377 
378 	f->setFTRaster ( wantDeviceDependant );
379 
380 //	if ( ui->loremView->isVisible() || ui->loremView_FT->isVisible() || layoutForPrint)
381 	{
382 		if(!layoutForPrint && !textLayoutFT->isLayoutFinished())
383 		{
384 			connect(textLayoutFT, SIGNAL(layoutFinished()), this, SLOT(slotView()));
385 			textLayoutFT->stopLayout();
386 			qDebug()<<"\tLayout stopped";
387 			layoutSwitch = false;
388 			return;
389 		}
390 		else
391 		{
392 			disconnect(textLayoutFT, SIGNAL(layoutFinished()), this, SLOT(slotView()));
393 		}
394 //		else if(textLayoutVect->isRunning())
395 //			textLayoutVect->stopLayout();
396 //		else
397 		{
398 			qDebug()<<"\tStart layout";
399 			ui->loremView_FT->unSheduleUpdate();
400 			ui->loremView->unSheduleUpdate();
401 			FMLayout * textLayout;
402 			if(layoutForPrint)
403 				textLayout = textLayoutVect;
404 			else
405 				textLayout = textLayoutFT;
406 
407 			bool processFeatures = f->isOpenType() &&  !deFillOTTree().isEmpty();
408 			QString script(sampleToolBar->getScript());
409 			bool processScript( !script.isEmpty() );
410 			textLayout->setDeviceIndy(!wantDeviceDependant);
411 			textLayout->setAdjustedSampleInter( sampleInterSize );
412 
413 			double fSize(sampleFontSize);
414 
415 			QList<GlyphList> list;
416 			QStringList stl( typotek::getInstance()->namedSample().split("\n"));
417 //			qDebug()<<"Sample:\n\t"<<stl.join("\n\t");
418 			if ( processScript )
419 			{
420 				for(int p(0);p<stl.count();++p)
421 				{
422 					list << f->glyphs( stl[p] , fSize, script );
423 				}
424 			}
425 			else if(processFeatures)
426 			{
427 				for(int p(0);p<stl.count();++p)
428 				{
429 					list << f->glyphs( stl[p] , fSize, deFillOTTree());
430 				}
431 			}
432 			else
433 			{
434 				for(int p(0);p<stl.count();++p)
435 					list << f->glyphs( stl[p] , fSize  );
436 			}
437 			if(!layoutForPrint)
438 			{
439 				layoutThread->setLayout(textLayout, list, fSize, f, hinting());
440 				connect(textLayout, SIGNAL(drawPixmapForMe(int,double,double,double)), this, SLOT(drawPixmap(int,double,double,double)));
441 //				connect(textLayoutFT, SIGNAL(drawBaselineForMe(double)), this, SLOT(drawBaseline(double)));
442 				connect(textLayout, SIGNAL(layoutFinished()), this, SLOT(endLayout()));
443 				layoutSwitch = true;
444 				pixmapDrawn = 0;
445 				layoutThread->start();
446 			}
447 			else
448 			{
449 				textLayout->doLayout(list, fSize);
450 			}
451 		}
452 	}
453 
454 }
455 
drawPixmap(int index,double fontsize,double x,double y)456 void SampleWidget::drawPixmap(int index, double fontsize, double x, double y)
457 {
458 //	qDebug()<<"SampleWidget::drawPixmap index:"<<index<< "Y:"<<y;
459 	if(index < 0)
460 		disconnect(textLayoutFT, SIGNAL(drawPixmapForMe(int,double,double,double)), this, SLOT(drawPixmap(int,double,double,double)));
461 	FontItem * f( FMFontDb::DB()->Font( fontIdentifier ) );
462 	if(!f)
463 		return;
464 	++pixmapDrawn;
465 	QGraphicsPixmapItem *glyph = f->itemFromGindexPix ( index , fontsize );
466 //	qDebug()<<"SampleWidget::drawPixmap index:"<<index<< y << glyph->data(GLYPH_DATA_BITMAPTOP).toDouble();
467 	ftScene->addItem ( glyph );
468 	glyph->setZValue ( 100.0 );
469 	glyph->setPos ( x,y );
470 //	QGraphicsLineItem * l = ftScene->addLine(x,y,x,y + glyph->data(GLYPH_DATA_BITMAPTOP).toDouble());
471 //	l->setData(GLYPH_DATA_GLYPH, 1);
472 //	glyph->pixmap().toImage().save(QString("/tmp/%1.png").arg(index));
473 }
474 
drawBaseline(double y)475 void SampleWidget::drawBaseline(double y)
476 {
477 	QGraphicsLineItem * l = ftScene->addLine(0,y,ftScene->width(),y);
478 	l->setData(GLYPH_DATA_GLYPH, 1);
479 }
480 
clearFTScene()481 void SampleWidget::clearFTScene()
482 {
483 	qDebug()<<"SampleWidget::clearFTScene"<< layoutSwitch;
484 //	if(layoutSwitch)
485 //		return;
486 	foreach(QGraphicsItem* gi, ftScene->items())
487 	{
488 		if(gi->data(GLYPH_DATA_GLYPH).toInt() > 0)
489 			delete gi;
490 	}
491 }
492 
endLayout()493 void SampleWidget::endLayout()
494 {
495 	QPointF texttopLeft(ui->loremView_FT->mapFromScene(textLayoutFT->getRect().topLeft()));
496 	ui->loremView_FT->translate( 10 -texttopLeft.x(), 10 -texttopLeft.y());
497 	ui->loremView_FT->update();
498 //	qDebug()<<"Pixmaps:"<<pixmapDrawn;
499 
500 }
501 
fillOTTree()502 void SampleWidget::fillOTTree()
503 {
504 	ui->OpenTypeTree->clear();
505 	ui->langCombo->clear();
506 	ui->langCombo->setEnabled ( false );
507 	ui->useShaperCheck->setCheckState ( Qt::Unchecked );
508 	ui->useShaperCheck->setEnabled ( false );
509 	typotek * typo(typotek::getInstance());
510 	QStringList scripts;
511 	FontItem * theVeryFont(FMFontDb::DB()->Font( fontIdentifier ));
512 	if ( theVeryFont && theVeryFont->isOpenType() )
513 	{
514 		FMOtf * otf = theVeryFont->takeOTFInstance();
515 		foreach ( QString table, otf->get_tables() )
516 		{
517 			otf->set_table ( table );
518 			QTreeWidgetItem *tab_item = new QTreeWidgetItem ( ui->OpenTypeTree,QStringList ( table ) );
519 			tab_item->setExpanded ( true );
520 			foreach ( QString script, otf->get_scripts() )
521 			{
522 				scripts << script;
523 				otf->set_script ( script );
524 				QTreeWidgetItem *script_item = new QTreeWidgetItem ( tab_item, QStringList ( script ) );
525 				script_item->setExpanded ( true );
526 				foreach ( QString lang, otf->get_langs() )
527 				{
528 					otf->set_lang ( lang );
529 					QTreeWidgetItem *lang_item = new QTreeWidgetItem ( script_item, QStringList ( lang ) );
530 					lang_item->setExpanded ( true );
531 					foreach ( QString feature, otf->get_features() )
532 					{
533 						QStringList f ( feature );
534 						f << OTTagMeans ( feature );
535 						QTreeWidgetItem *feature_item = new QTreeWidgetItem ( lang_item, f );
536 						feature_item->setCheckState ( 0, Qt::Unchecked );
537 						if(table == "GPOS")
538 						{
539 							if(typo->getDefaultOTFScript() == script && typo->getDefaultOTFLang() == lang && typo->getDefaultOTFGPOS().contains(feature) )
540 							{
541 								feature_item->setCheckState ( 0, Qt::Checked );
542 							}
543 						}
544 						else if(table == "GSUB")
545 						{
546 							if(typo->getDefaultOTFScript() == script && typo->getDefaultOTFLang() == lang && typo->getDefaultOTFGSUB().contains(feature) )
547 							{
548 								feature_item->setCheckState ( 0, Qt::Checked );
549 							}
550 						}
551 					}
552 				}
553 			}
554 		}
555 		ui->OpenTypeTree->resizeColumnToContents ( 0 ) ;
556 		theVeryFont->releaseOTFInstance ( otf );
557 	}
558 	scripts = scripts.toSet().toList();
559 	// 	scripts.removeAll ( "latn" );
560 //	if ( !scripts.isEmpty() )
561 	{
562 //		ui->langCombo->setEnabled ( true );
563 //		ui->useShaperCheck->setEnabled ( true );
564 //		ui->langCombo->addItems ( scripts );
565 		sampleToolBar->setScripts(scripts);
566 	}
567 }
568 
deFillOTTree()569 OTFSet SampleWidget::deFillOTTree()
570 {
571 	// 	qDebug() << "MainViewWidget::deFillOTTree()";
572 	OTFSet ret;
573 	// 	qDebug() << ui->OpenTypeTree->topLevelItemCount();
574 	for ( int table_index = 0; table_index < ui->OpenTypeTree->topLevelItemCount(); ++table_index ) //tables
575 	{
576 		// 		qDebug() << "table_index = " << table_index;
577 		QTreeWidgetItem * table_item = ui->OpenTypeTree->topLevelItem ( table_index ) ;
578 		// 		qDebug() <<  table_item->text(0);
579 		for ( int script_index = 0; script_index < table_item->childCount();++script_index ) //scripts
580 		{
581 			QTreeWidgetItem * script_item = table_item->child ( script_index );
582 			// 			qDebug() << "\tscript_index = " <<  script_index << script_item->text(0);
583 			for ( int lang_index = 0; lang_index < script_item->childCount(); ++lang_index ) //langs
584 			{
585 				QTreeWidgetItem * lang_item = script_item->child ( lang_index );
586 				// 				qDebug() << "\t\tlang_index = "<< lang_index << lang_item->text(0);
587 				for ( int feature_index = 0; feature_index < lang_item->childCount(); ++feature_index ) //features
588 				{
589 					// 					qDebug() << lang_item->childCount() <<" / "<<  feature_index;
590 					QTreeWidgetItem * feature_item = lang_item->child ( feature_index );
591 					// 					qDebug() << "\t\t\tfeature_item -> "<< feature_item->text(0);
592 					if ( feature_item->checkState ( 0 ) == Qt::Checked )
593 					{
594 						if ( table_item->text ( 0 ) == "GPOS" )
595 						{
596 							ret.script = script_item->text ( 0 );
597 							ret.lang = lang_item->text ( 0 );
598 							ret.gpos_features.append ( feature_item->text ( 0 ) );
599 						}
600 						if ( table_item->text ( 0 ) == "GSUB" )
601 						{
602 							ret.script = script_item->text ( 0 );
603 							ret.lang = lang_item->text ( 0 );
604 							ret.gsub_features.append ( feature_item->text ( 0 ) );
605 						}
606 					}
607 				}
608 			}
609 		}
610 	}
611 	// 	qDebug() << "endOf";
612 	return ret;
613 
614 }
615 
616 //void SampleWidget::slotChangeViewPage(QAbstractButton* but)
617 //{
618 //	QString radioName( but->objectName() );
619 
620 //	if(radioName == "freetypeRadio" )
621 //	{
622 //		ui->stackedViews->setCurrentIndex(VIEW_PAGE_FREETYPE);
623 //		ui->hintingSelect->setEnabled(true);
624 //	}
625 //	else if(radioName == "nativeRadio" )
626 //	{
627 //		ui->stackedViews->setCurrentIndex(VIEW_PAGE_ABSOLUTE);
628 //		ui->hintingSelect->setEnabled(false);
629 //	}
630 
631 //	slotView(true);
632 //}
633 
634 //void SampleWidget::slotHintChanged(int )
635 //{
636 //	slotView(true);
637 //	emit stateChanged();
638 //}
639 
640 
641 //void SampleWidget::slotChangeViewPageSetting ( bool ch )
642 //{
643 //	// 	qDebug() <<"MainViewWidget::slotChangeViewPageSetting("<<ch<<")";
644 //	QString butName ( sender()->objectName() );
645 //	if ( !ch )
646 //	{
647 //		toolPanelWidth = ui->splitter_2->sizes().at ( 1 ) ;
648 //		ui->stackedTools->hide();
649 //	}
650 //	else
651 //	{
652 //		ui->stackedTools->show();
653 //		if ( ui->splitter_2->sizes().at ( 1 ) == 0 )
654 //		{
655 //			QList<int> li;
656 //			li << ui->splitter_2->width() - toolPanelWidth << toolPanelWidth;
657 //			ui->splitter_2->setSizes ( li );
658 //		}
659 //	}
660 
661 //	QMap<QString, QToolButton*> bmap;
662 //	QMap<QString, int> pmap;
663 //	bmap[ "settingsButton" ] = ui->settingsButton;
664 //	bmap[ "openTypeButton" ] = ui->openTypeButton;
665 //	bmap[ "sampleButton" ] = ui->sampleButton;
666 //	pmap[ "settingsButton" ] = VIEW_PAGE_SETTINGS;
667 //	pmap[ "openTypeButton" ] = VIEW_PAGE_OPENTYPE;
668 //	pmap[ "sampleButton" ] = VIEW_PAGE_SAMPLES;
669 
670 //	foreach(QString pk, bmap.keys())
671 //	{
672 //		if(butName == pk)
673 //		{
674 //			ui->stackedTools->setCurrentIndex(pmap[pk]);
675 //		}
676 //		else
677 //		{
678 //			bmap[pk]->setChecked ( false );
679 //		}
680 //	}
681 //}
682 
683 
slotUpdateSView()684 void SampleWidget::slotUpdateSView()
685 {
686 	if(ui->loremView->isVisible())
687 		slotView();
688 }
689 
690 
slotZoom(int z)691 void SampleWidget::slotZoom ( int z )
692 {
693 	double delta =  1.0 + ( z/1000.0 ) ;
694 	QTransform trans;
695 	trans.scale ( delta,delta );
696 
697 	QGraphicsView * concernedView;
698 	if ( ui->loremView_FT->isVisible() )
699 		concernedView = ui->loremView_FT;
700 	else if ( ui->loremView->isVisible() )
701 	{
702 		concernedView = ui->loremView;
703 		if ( delta == 1.0 )
704 		{
705 			double horiScaleT (typotek::getInstance()->getDpiX() / 72.0);
706 			double vertScaleT ( typotek::getInstance()->getDpiY() / 72.0);
707 			QTransform adjustAbsoluteViewT( horiScaleT , 0, 0,vertScaleT, 0, 0 );
708 			trans =  adjustAbsoluteViewT;
709 		}
710 	}
711 	concernedView->setTransform ( trans, ( z == 0 ) ? false : true );
712 
713 }
714 
715 
slotUpdateRView()716 void SampleWidget::slotUpdateRView()
717 {
718 	if(ui->loremView_FT->isVisible())
719 		slotView();
720 }
721 
slotSampleChanged()722 void SampleWidget::slotSampleChanged()
723 {
724 	typotek::getInstance()->namedSample( ui->sampleTextTree->currentItem()->data(0, Qt::UserRole).toString() );
725 	ui->removeSampleButton->setEnabled(ui->sampleTextTree->currentItem()->parent() == uRoot);
726 	slotView (  );
727 	emit stateChanged();
728 }
729 
730 
731 
slotLiveFontSize(double fs)732 void SampleWidget::slotLiveFontSize(double fs)
733 {
734 //	double fs( sampleToolBar->getFontSize() );
735 	reSize(fs, fs * sampleRatio);
736 	slotView();
737 	emit stateChanged();
738 }
739 
slotFeatureChanged()740 void SampleWidget::slotFeatureChanged()
741 {
742 	// 	OTFSet ret = deFillOTTree();
743 	slotView (  );
744 	emit stateChanged();
745 }
746 
slotDefaultOTF()747 void SampleWidget::slotDefaultOTF()
748 {
749 	OTFSet ots(deFillOTTree());
750 	typotek* typo(typotek::getInstance());
751 	typo->setDefaultOTFScript(ots.script);
752 	typo->setDefaultOTFLang(ots.lang);
753 	typo->setDefaultOTFGPOS(ots.gpos_features);
754 	typo->setDefaultOTFGSUB(ots.gsub_features);
755 }
756 
slotResetOTF()757 void SampleWidget::slotResetOTF()
758 {
759 	typotek* typo(typotek::getInstance());
760 	typo->setDefaultOTFScript(QString());
761 	typo->setDefaultOTFLang(QString());
762 	typo->setDefaultOTFGPOS(QStringList());
763 	typo->setDefaultOTFGSUB(QStringList());
764 }
765 
766 
slotChangeScript()767 void SampleWidget::slotChangeScript()
768 {
769 	if ( ui->useShaperCheck->checkState() == Qt::Checked )
770 	{
771 		slotView (  );
772 	}
773 	emit stateChanged();
774 }
775 
slotProgressionChanged()776 void SampleWidget::slotProgressionChanged()
777 {
778 	slotView();
779 }
780 
slotWantShape()781 void SampleWidget::slotWantShape()
782 {
783 	slotView (  );
784 	emit stateChanged();
785 }
786 
787 
refillSampleList()788 void SampleWidget::refillSampleList()
789 {
790 	ui->sampleTextTree->clear();
791 
792 	QTreeWidgetItem * curIt = 0;
793 	QMap<QString, QList<QString> > sl = typotek::getInstance()->namedSamplesNames();
794 	QList<QString> ul( sl.take(QString("User")) );
795 	uRoot = new QTreeWidgetItem(ui->sampleTextTree);
796 	//: Identify root of user defined sample texts
797 	uRoot->setText(0, tr("User"));
798 	if(ul.count())
799 	{
800 
801 		bool first(true);
802 		foreach(QString uk, ul)
803 		{
804 			if(first)
805 			{
806 				first = false;
807 				uRoot->setData(0, Qt::UserRole , QString("User::") + uk);
808 				curIt = uRoot;
809 			}
810 			QTreeWidgetItem * it = new QTreeWidgetItem();
811 			it->setText(0, uk);
812 			it->setData(0, Qt::UserRole , QString("User::") + uk);
813 			uRoot->addChild(it);
814 		}
815 	}
816 	foreach(QString k, sl.keys())
817 	{
818 		QTreeWidgetItem * kRoot = new QTreeWidgetItem(ui->sampleTextTree);
819 		kRoot->setText(0, k);
820 		bool first(true);
821 		foreach(QString n, sl[k])
822 		{
823 			if(first)
824 			{
825 				first = false;
826 				kRoot->setData(0, Qt::UserRole , k + QString("::") + n);
827 				if(!curIt)
828 					curIt = kRoot;
829 			}
830 			QTreeWidgetItem * it = new QTreeWidgetItem();
831 			it->setText(0, n);
832 			it->setData(0, Qt::UserRole, k + QString("::") + n);
833 			kRoot->addChild(it);
834 		}
835 	}
836 
837 	ui->sampleTextTree->setCurrentItem(curIt);
838 }
839 
hinting()840 unsigned int SampleWidget::hinting()
841 {
842 //	if(ui->lightHinting->isChecked())
843 //		return FT_LOAD_TARGET_LIGHT;
844 //	else if(ui->normalHinting->isChecked())
845 //		return FT_LOAD_TARGET_NORMAL;
846 
847 	return FT_LOAD_NO_HINTING ;
848 }
849 
850 
slotPrint()851 void SampleWidget::slotPrint()
852 {
853 	FontItem * font(FMFontDb::DB()->Font( fontIdentifier ));
854 	if(!font)
855 		return;
856 
857 	if(printer == 0)
858 		printer = new QPrinter(QPrinter::HighResolution);
859 	if(printDialog == 0)
860 		printDialog = new QPrintDialog(printer, this);
861 
862 	printDialog->setWindowTitle("Fontmatrix - " + tr("Print Sample") +" - " + font->fancyName() );
863 	printDialog->open(this, SLOT(slotDoPrinting()));
864 }
865 
866 
slotDoPrinting()867 void SampleWidget::slotDoPrinting()
868 {
869 	layoutForPrint = true;
870 	slotView();
871 	printer->setFullPage ( true );
872 	QPainter aPainter ( printer );
873 	loremScene->render(&aPainter);
874 	layoutForPrint = false;
875 }
876 
slotFileChanged(const QString &)877 void SampleWidget::slotFileChanged(const QString &)
878 {
879 #ifdef PLATFORM_APPLE
880 	if(fileInfo.lastModified().toMSecsSinceEpoch() == fileLastModified)
881 		return;
882 	fileLastModified = fileInfo.lastModified().toMSecsSinceEpoch();
883 #endif
884 	if(reloadTimer->isActive())
885 		reloadTimer->start();
886 	else
887 	{
888 		reloadTimer->start();
889 	}
890 }
891 
slotReload()892 void SampleWidget::slotReload()
893 {
894 //	reloadTimer->stop();
895 	slotView();
896 }
897 
slotScriptChange()898 void SampleWidget::slotScriptChange()
899 {
900 	slotView();
901 }
902 
saveState()903 void SampleWidget::saveState()
904 {
905 	QSettings settings;
906 	State s(state());
907 	QByteArray bs(s.toByteArray());
908 	settings.setValue("Sample/state", bs);
909 }
910 
slotShowSamples(bool b)911 void SampleWidget::slotShowSamples(bool b)
912 {
913 	if(b)
914 	{
915 		if(sampleToolBar->isChecked(SampleToolBar::OpenTypeButton))
916 		{
917 			ui->sampleGridLayout->removeWidget(ui->opentypeWidget);
918 			ui->opentypeWidget->setParent(ui->stackedViews->widget(VIEW_PAGE_OPENTYPE));
919 			sampleToolBar->toggle(SampleToolBar::OpenTypeButton, false);
920 		}
921 		ui->sampleEditWidget->setAutoFillBackground(true);
922 		ui->sampleEditWidget->resize(ui->sampleGridLayout->geometry().width() / 2, ui->sampleGridLayout->geometry().height());
923 		ui->sampleGridLayout->addWidget(ui->sampleEditWidget, 0,0, Qt::AlignRight);
924 	}
925 	else
926 	{
927 		ui->sampleGridLayout->removeWidget(ui->sampleEditWidget);
928 		ui->sampleEditWidget->setParent(ui->stackedViews->widget(VIEW_PAGE_SAMPLES));
929 	}
930 }
931 
slotShowOpenType(bool b)932 void SampleWidget::slotShowOpenType(bool b)
933 {
934 	if(b)
935 	{
936 		if(sampleToolBar->isChecked(SampleToolBar::SampleButton))
937 		{
938 			ui->sampleGridLayout->removeWidget(ui->sampleEditWidget);
939 			ui->sampleEditWidget->setParent(ui->stackedViews->widget(VIEW_PAGE_SAMPLES));
940 			sampleToolBar->toggle(SampleToolBar::SampleButton, false);
941 		}
942 		ui->opentypeWidget->setAutoFillBackground(true);
943 		ui->opentypeWidget->resize(ui->sampleGridLayout->geometry().width() / 2, ui->sampleGridLayout->geometry().height());
944 		ui->sampleGridLayout->addWidget(ui->opentypeWidget, 0,0, Qt::AlignRight);
945 	}
946 	else
947 	{
948 		ui->sampleGridLayout->removeWidget(ui->opentypeWidget);
949 		ui->opentypeWidget->setParent(ui->stackedViews->widget(VIEW_PAGE_OPENTYPE));
950 	}
951 }
952 
slotAddSample()953 void SampleWidget::slotAddSample()
954 {
955 	QString nu( tr("New Sample") );
956 	newSampleName = new QTreeWidgetItem();
957 	newSampleName->setText(0,nu);
958 	newSampleName->setData(0, Qt::UserRole , QString("NEW_SAMPLE"));
959 	newSampleName->setFlags(newSampleName->flags() | Qt::ItemIsEditable);
960 	uRoot->addChild(newSampleName);
961 	ui->sampleTextTree->openPersistentEditor(newSampleName);
962 	if(!uRoot->isExpanded())
963 		uRoot->setExpanded(true);
964 	ui->sampleTextTree->setCurrentItem(newSampleName);
965 }
966 
slotSampleNameEdited(QWidget * w)967 void SampleWidget::slotSampleNameEdited(QWidget *w)
968 {
969 	ui->sampleTextTree->closePersistentEditor(newSampleName);
970 	newSampleName->setData(0, Qt::UserRole , QString("User::") + newSampleName->text(0));
971 	typotek::getInstance()->changeSample(newSampleName->text(0), ui->sampleEdit->toPlainText() );
972 }
973 
slotRemoveSample()974 void SampleWidget::slotRemoveSample()
975 {
976 	QString name(ui->sampleTextTree->currentItem()->text(0));
977 	QTreeWidgetItem * currentItem = ui->sampleTextTree->currentItem();
978 	uRoot->removeChild(currentItem);
979 	typotek::getInstance()->removeNamedSample(name);
980 }
981 
slotEditSample()982 void SampleWidget::slotEditSample()
983 {
984 	disconnect(ui->sampleEdit, SIGNAL(textChanged()), this, SLOT(slotUpdateSample()));
985 	QTreeWidgetItem * currentItem = ui->sampleTextTree->currentItem();
986 	ui->sampleEdit->setPlainText(typotek::getInstance()->namedSample( currentItem->data(0, Qt::UserRole).toString() ));
987 	ui->sampleEdit->setReadOnly(currentItem->parent() != uRoot);
988 	connect(ui->sampleEdit, SIGNAL(textChanged()), this, SLOT(slotUpdateSample()));
989 }
990 
slotUpdateSample()991 void SampleWidget::slotUpdateSample()
992 {
993 	typotek::getInstance()->changeSample(ui->sampleTextTree->currentItem()->text(0), ui->sampleEdit->toPlainText());
994 	slotView();
995 }
996 
997