You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
digikam/digikam/imageplugins/inserttext/fontchooserwidget.cpp

739 lines
23 KiB

/* ============================================================
*
* This file is a part of digiKam project
* http://www.digikam.org
*
* Date : 2005-02-14
* Description : a simple widget to choose a font based on
* KDE FontChooserWidget implementation.
*
* Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com>
* Copyright (C) 1999 by Preston Brown <pbrown@kde.org>
* Copyright (C) 1997 by Bernd Johannes Wuebben <wuebben@kde.org>
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software Foundation;
* either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* ============================================================ */
// TQt includes.
#include <tqcheckbox.h>
#include <tqcombobox.h>
#include <tqfile.h>
#include <tqfont.h>
#include <tqfontdatabase.h>
#include <tqgroupbox.h>
#include <tqlabel.h>
#include <tqlayout.h>
#include <tqscrollbar.h>
#include <tqspinbox.h>
#include <tqstringlist.h>
#include <tqtooltip.h>
#include <tqwhatsthis.h>
// KDE includes.
#include <kapplication.h>
#include <kcharsets.h>
#include <tdeconfig.h>
#include <kdialog.h>
#include <kglobal.h>
#include <kglobalsettings.h>
#include <klistbox.h>
#include <klocale.h>
#include <knuminput.h>
#include <kstandarddirs.h>
#include <tqlineedit.h>
// Local includes.
#include "fontchooserwidget.h"
#include "fontchooserwidget.moc"
namespace DigikamInsertTextImagesPlugin
{
class FontChooserWidget::FontChooserWidgetPrivate
{
public:
FontChooserWidgetPrivate()
{
m_palette.setColor(TQPalette::Active, TQColorGroup::Text, TQt::black);
m_palette.setColor(TQPalette::Active, TQColorGroup::Base, TQt::white);
}
TQPalette m_palette;
};
FontChooserWidget::FontChooserWidget(TQWidget *parent, const char *name,
bool onlyFixed, const TQStringList &fontList,
int visibleListSize, bool diff,
TQButton::ToggleState *sizeIsRelativeState )
: TQWidget(parent, name), usingFixed(onlyFixed)
{
charsetsCombo = 0;
TQString mainWhatsThisText = i18n( "Here you can choose the font to be used." );
TQWhatsThis::add( this, mainWhatsThisText );
d = new FontChooserWidgetPrivate;
TQVBoxLayout *topLayout = new TQVBoxLayout( this, 0, KDialog::spacingHint() );
int checkBoxGap = KDialog::spacingHint() / 2;
int row = 0;
TQWidget *page = new TQWidget( this );
topLayout->addWidget(page);
TQGridLayout *gridLayout = new TQGridLayout( page, 4, 3, 0, KDialog::spacingHint() );
// First, create the labels across the top
TQHBoxLayout *familyLayout = new TQHBoxLayout();
familyLayout->addSpacing( checkBoxGap );
if (diff)
{
familyCheckbox = new TQCheckBox(i18n("Font"), page);
connect(familyCheckbox, TQT_SIGNAL(toggled(bool)),
this, TQT_SLOT(toggled_checkbox()));
familyLayout->addWidget(familyCheckbox, 0, TQt::AlignLeft);
TQString familyCBToolTipText =
i18n("Change font family?");
TQString familyCBWhatsThisText =
i18n("Enable this checkbox to change the font family settings.");
TQWhatsThis::add( familyCheckbox, familyCBWhatsThisText );
TQToolTip::add( familyCheckbox, familyCBToolTipText );
familyLabel = 0;
}
else
{
familyCheckbox = 0;
familyLabel = new TQLabel( i18n("Font:"), page, "familyLabel" );
familyLayout->addWidget(familyLabel, 1, TQt::AlignLeft);
}
gridLayout->addLayout(familyLayout, row, 0 );
TQHBoxLayout *styleLayout = new TQHBoxLayout();
if (diff)
{
styleCheckbox = new TQCheckBox(i18n("Style:"), page);
connect(styleCheckbox, TQT_SIGNAL(toggled(bool)),
this, TQT_SLOT(toggled_checkbox()));
styleLayout->addWidget(styleCheckbox, 0, TQt::AlignLeft);
TQString styleCBToolTipText =
i18n("Change font style?");
TQString styleCBWhatsThisText =
i18n("Enable this checkbox to change the font style settings.");
TQWhatsThis::add( styleCheckbox, styleCBWhatsThisText );
TQToolTip::add( styleCheckbox, styleCBToolTipText );
styleLabel = 0;
}
else
{
styleCheckbox = 0;
styleLabel = new TQLabel( i18n("Style:"), page, "styleLabel");
styleLayout->addWidget(styleLabel, 1, TQt::AlignLeft);
}
styleLayout->addSpacing( checkBoxGap );
gridLayout->addLayout(styleLayout, row, 1 );
TQHBoxLayout *sizeLayout = new TQHBoxLayout();
if (diff)
{
sizeCheckbox = new TQCheckBox(i18n("Size"),page);
connect(sizeCheckbox, TQT_SIGNAL(toggled(bool)),
this, TQT_SLOT(toggled_checkbox()));
sizeLayout->addWidget(sizeCheckbox, 0, TQt::AlignLeft);
TQString sizeCBToolTipText =
i18n("Change font size?");
TQString sizeCBWhatsThisText =
i18n("Enable this checkbox to change the font size settings.");
TQWhatsThis::add( sizeCheckbox, sizeCBWhatsThisText );
TQToolTip::add( sizeCheckbox, sizeCBToolTipText );
sizeLabel = 0;
}
else
{
sizeCheckbox = 0;
sizeLabel = new TQLabel( i18n("Size:"), page, "sizeLabel");
sizeLayout->addWidget(sizeLabel, 1, TQt::AlignLeft);
}
sizeLayout->addSpacing( checkBoxGap );
sizeLayout->addSpacing( checkBoxGap ); // prevent label from eating border
gridLayout->addLayout(sizeLayout, row, 2 );
row ++;
// Now create the actual boxes that hold the info
familyListBox = new KListBox( page, "familyListBox");
familyListBox->setEnabled( !diff );
gridLayout->addWidget( familyListBox, row, 0 );
TQString fontFamilyWhatsThisText = i18n("Here you can choose the font family to be used." );
TQWhatsThis::add( familyListBox, fontFamilyWhatsThisText );
TQWhatsThis::add(diff?(TQWidget *) familyCheckbox:(TQWidget *) familyLabel, fontFamilyWhatsThisText );
connect(familyListBox, TQT_SIGNAL(highlighted(const TQString &)),
this, TQT_SLOT(family_chosen_slot(const TQString &)));
if(!fontList.isEmpty())
{
familyListBox->insertStringList(fontList);
}
else
{
fillFamilyListBox(onlyFixed);
}
familyListBox->setMinimumHeight( minimumListHeight( familyListBox, visibleListSize ) );
styleListBox = new KListBox( page, "styleListBox");
styleListBox->setEnabled( !diff );
gridLayout->addWidget(styleListBox, row, 1);
TQString fontStyleWhatsThisText = i18n("Here you can choose the font style to be used." );
TQWhatsThis::add( styleListBox, fontStyleWhatsThisText );
TQWhatsThis::add(diff?(TQWidget *)styleCheckbox:(TQWidget *)styleLabel, fontFamilyWhatsThisText );
styleListBox->insertItem(i18n("Regular"));
styleListBox->insertItem(i18n("Italic"));
styleListBox->insertItem(i18n("Bold"));
styleListBox->insertItem(i18n("Bold Italic"));
styleListBox->setMinimumWidth( minimumListWidth( styleListBox ) );
styleListBox->setMinimumHeight( minimumListHeight( styleListBox, visibleListSize ) );
connect(styleListBox, TQT_SIGNAL(highlighted(const TQString &)),
this, TQT_SLOT(style_chosen_slot(const TQString &)));
sizeListBox = new KListBox( page, "sizeListBox");
sizeOfFont = new KIntNumInput( page, "sizeOfFont");
sizeOfFont->setMinValue(4);
sizeListBox->setEnabled( !diff );
sizeOfFont->setEnabled( !diff );
if( sizeIsRelativeState )
{
TQString sizeIsRelativeCBText =
i18n("Relative");
TQString sizeIsRelativeCBToolTipText =
i18n("Font size<br><i>fixed</i> or <i>relative</i><br>to environment");
TQString sizeIsRelativeCBWhatsThisText =
i18n("Here you can switch between fixed a font size and a font size "
"to be calculated dynamically and adjusted to any changing "
"environment (e.g. widget dimensions, paper size)." );
sizeIsRelativeCheckBox = new TQCheckBox( sizeIsRelativeCBText,
page,
"sizeIsRelativeCheckBox" );
sizeIsRelativeCheckBox->setTristate( diff );
TQGridLayout *sizeLayout2 = new TQGridLayout( 3,2, KDialog::spacingHint()/2, "sizeLayout2" );
gridLayout->addLayout(sizeLayout2, row, 2);
sizeLayout2->setColStretch( 1, 1 ); // to prevent text from eating the right border
sizeLayout2->addMultiCellWidget( sizeOfFont, 0, 0, 0, 1);
sizeLayout2->addMultiCellWidget(sizeListBox, 1,1, 0,1);
sizeLayout2->addWidget(sizeIsRelativeCheckBox, 2, 0, TQt::AlignLeft);
TQWhatsThis::add( sizeIsRelativeCheckBox, sizeIsRelativeCBWhatsThisText );
TQToolTip::add( sizeIsRelativeCheckBox, sizeIsRelativeCBToolTipText );
}
else
{
sizeIsRelativeCheckBox = 0L;
TQGridLayout *sizeLayout2 = new TQGridLayout( 2,1, KDialog::spacingHint()/2, "sizeLayout2" );
gridLayout->addLayout(sizeLayout2, row, 2);
sizeLayout2->addWidget( sizeOfFont, 0, 0);
sizeLayout2->addMultiCellWidget(sizeListBox, 1,1, 0,0);
}
TQString fontSizeWhatsThisText = i18n("Here you can choose the font size to be used." );
TQWhatsThis::add( sizeListBox, fontSizeWhatsThisText );
TQWhatsThis::add( diff?(TQWidget *)sizeCheckbox:(TQWidget *)sizeLabel, fontSizeWhatsThisText );
fillSizeList();
sizeListBox->setMinimumWidth( minimumListWidth(sizeListBox) +
sizeListBox->fontMetrics().maxWidth() );
sizeListBox->setMinimumHeight( minimumListHeight( sizeListBox, visibleListSize ) );
connect( sizeOfFont, TQT_SIGNAL( valueChanged(int) ),
this, TQT_SLOT(size_value_slot(int)));
connect( sizeListBox, TQT_SIGNAL(highlighted(const TQString&)),
this, TQT_SLOT(size_chosen_slot(const TQString&)) );
sizeListBox->setSelected(sizeListBox->findItem(TQString::number(10)), true); // default to 10pt.
row ++;
row ++;
TQVBoxLayout *vbox;
page = new TQWidget( this );
topLayout->addWidget(page);
vbox = new TQVBoxLayout( page, 0, KDialog::spacingHint() );
TQLabel *label = new TQLabel( i18n("Actual Font"), page );
vbox->addWidget( label );
xlfdEdit = new TQLineEdit( page, "xlfdEdit" );
vbox->addWidget( xlfdEdit );
// lets initialize the display if possible
setFont( TDEGlobalSettings::generalFont(), usingFixed );
// check or uncheck or gray out the "relative" checkbox
if( sizeIsRelativeState && sizeIsRelativeCheckBox )
setSizeIsRelative( *sizeIsRelativeState );
TDEConfig *config = TDEGlobal::config();
TDEConfigGroupSaver saver(config, TQString::fromLatin1("General"));
showXLFDArea(config->readBoolEntry(TQString::fromLatin1("fontSelectorShowXLFD"), false));
}
FontChooserWidget::~FontChooserWidget()
{
delete d;
}
int FontChooserWidget::minimumListWidth( const TQListBox *list )
{
int w=0;
for( uint i=0; i<list->count(); i++ )
{
int itemWidth = list->item(i)->width(list);
w = TQMAX(w,itemWidth);
}
if( w == 0 )
{
w = 40;
}
w += list->frameWidth() * 2;
w += list->verticalScrollBar()->sizeHint().width();
return w;
}
int FontChooserWidget::minimumListHeight( const TQListBox *list, int numVisibleEntry )
{
int w = list->count() > 0 ? list->item(0)->height(list) :
list->fontMetrics().lineSpacing();
if( w < 0 ) { w = 10; }
if( numVisibleEntry <= 0 ) { numVisibleEntry = 4; }
return ( w * numVisibleEntry + 2 * list->frameWidth() );
}
void FontChooserWidget::fillSizeList()
{
if(! sizeListBox) return; //assertion.
static const int c[] =
{
4, 5, 6, 7,
8, 9, 10, 11,
12, 13, 14, 15,
16, 17, 18, 19,
20, 22, 24, 26,
28, 32, 48, 64,
72, 80, 94, 102,
116, 128, 132, 148,
156, 164, 172, 188,
192, 202, 212, 224,
232, 240, 248, 256,
0
};
for(int i = 0; c[i]; ++i)
{
sizeListBox->insertItem(TQString::number(c[i]));
}
}
void FontChooserWidget::setColor( const TQColor & col )
{
d->m_palette.setColor( TQPalette::Active, TQColorGroup::Text, col );
}
TQColor FontChooserWidget::color() const
{
return d->m_palette.color( TQPalette::Active, TQColorGroup::Text );
}
void FontChooserWidget::setBackgroundColor( const TQColor & col )
{
d->m_palette.setColor( TQPalette::Active, TQColorGroup::Base, col );
}
TQColor FontChooserWidget::backgroundColor() const
{
return d->m_palette.color( TQPalette::Active, TQColorGroup::Base );
}
void FontChooserWidget::setSizeIsRelative( TQButton::ToggleState relative )
{
// check or uncheck or gray out the "relative" checkbox
if( sizeIsRelativeCheckBox )
{
if( TQButton::NoChange == relative )
sizeIsRelativeCheckBox->setNoChange();
else
sizeIsRelativeCheckBox->setChecked( TQButton::On == relative );
}
}
TQButton::ToggleState FontChooserWidget::sizeIsRelative() const
{
return sizeIsRelativeCheckBox
? sizeIsRelativeCheckBox->state()
: TQButton::NoChange;
}
TQSize FontChooserWidget::sizeHint( void ) const
{
return minimumSizeHint();
}
void FontChooserWidget::enableColumn( int column, bool state )
{
if( column & FamilyList )
{
familyListBox->setEnabled(state);
}
if( column & StyleList )
{
styleListBox->setEnabled(state);
}
if( column & SizeList )
{
sizeListBox->setEnabled(state);
}
}
void FontChooserWidget::setFont( const TQFont& aFont, bool onlyFixed )
{
selFont = aFont;
selectedSize=aFont.pointSize();
if (selectedSize == -1)
selectedSize = TQFontInfo(aFont).pointSize();
if( onlyFixed != usingFixed)
{
usingFixed = onlyFixed;
fillFamilyListBox(usingFixed);
}
setupDisplay();
displaySample(selFont);
}
int FontChooserWidget::fontDiffFlags() {
int diffFlags = 0;
if (familyCheckbox && styleCheckbox && sizeCheckbox)
{
diffFlags = (int)(familyCheckbox->isChecked() ? FontDiffFamily : 0)
| (int)( styleCheckbox->isChecked() ? FontDiffStyle : 0)
| (int)( sizeCheckbox->isChecked() ? FontDiffSize : 0);
}
return diffFlags;
}
void FontChooserWidget::toggled_checkbox()
{
familyListBox->setEnabled( familyCheckbox->isChecked() );
styleListBox->setEnabled( styleCheckbox->isChecked() );
sizeListBox->setEnabled( sizeCheckbox->isChecked() );
sizeOfFont->setEnabled( sizeCheckbox->isChecked() );
}
void FontChooserWidget::family_chosen_slot(const TQString& family)
{
TQFontDatabase dbase;
TQStringList styles = TQStringList(dbase.styles(family));
styleListBox->clear();
currentStyles.clear();
TQStringList::Iterator end(styles.end());
for ( TQStringList::Iterator it = styles.begin(); it != end; ++it )
{
TQString style = *it;
int pos = style.find("Plain");
if(pos >=0) style = style.replace(pos,5,i18n("Regular"));
pos = style.find("Normal");
if(pos >=0) style = style.replace(pos,6,i18n("Regular"));
pos = style.find("Oblique");
if(pos >=0) style = style.replace(pos,7,i18n("Italic"));
if(!styleListBox->findItem(style))
{
styleListBox->insertItem(i18n(style.utf8()));
currentStyles.insert(i18n(style.utf8()), *it);
}
}
if(styleListBox->count()==0)
{
styleListBox->insertItem(i18n("Regular"));
currentStyles.insert(i18n("Regular"), "Normal");
}
styleListBox->blockSignals(true);
TQListBoxItem *item = styleListBox->findItem(selectedStyle);
if (item)
styleListBox->setSelected(styleListBox->findItem(selectedStyle), true);
else
styleListBox->setSelected(0, true);
styleListBox->blockSignals(false);
style_chosen_slot(TQString());
}
void FontChooserWidget::size_chosen_slot(const TQString& size)
{
selectedSize=size.toInt();
sizeOfFont->setValue(selectedSize);
selFont.setPointSize(selectedSize);
emit fontSelected(selFont);
}
void FontChooserWidget::size_value_slot(int val)
{
selFont.setPointSize(val);
emit fontSelected(selFont);
}
void FontChooserWidget::style_chosen_slot(const TQString& style)
{
TQString currentStyle;
if (style.isEmpty())
currentStyle = styleListBox->currentText();
else
currentStyle = style;
int diff=0; // the difference between the font size requested and what we can show.
sizeListBox->clear();
TQFontDatabase dbase;
if(dbase.isSmoothlyScalable(familyListBox->currentText(), currentStyles[currentStyle]))
{ // is vector font
//sampleEdit->setPaletteBackgroundPixmap( VectorPixmap ); // TODO
fillSizeList();
}
else
{ // is bitmap font.
//sampleEdit->setPaletteBackgroundPixmap( BitmapPixmap ); // TODO
TQValueList<int> sizes = dbase.smoothSizes(familyListBox->currentText(), currentStyles[currentStyle]);
if(sizes.count() > 0)
{
TQValueList<int>::iterator it;
diff=1000;
TQValueList<int>::iterator end(sizes.end());
for ( it = sizes.begin(); it != end; ++it )
{
if(*it <= selectedSize || diff > *it - selectedSize) diff = selectedSize - *it;
sizeListBox->insertItem(TQString::number(*it));
}
}
else // there are times QT does not provide the list..
fillSizeList();
}
sizeListBox->blockSignals(true);
sizeListBox->setSelected(sizeListBox->findItem(TQString::number(selectedSize)), true);
sizeListBox->blockSignals(false);
sizeListBox->ensureCurrentVisible();
selFont = dbase.font(familyListBox->currentText(), currentStyles[currentStyle], selectedSize-diff);
emit fontSelected(selFont);
if (!style.isEmpty())
selectedStyle = style;
}
void FontChooserWidget::displaySample(const TQFont& font)
{
xlfdEdit->setText(font.rawName());
xlfdEdit->setCursorPosition(0);
}
void FontChooserWidget::setupDisplay()
{
// Calling familyListBox->setCurrentItem() causes the value of selFont
// to change, so we save the family, style and size beforehand.
TQString family = selFont.family().lower();
int style = (selFont.bold() ? 2 : 0) + (selFont.italic() ? 1 : 0);
int size = selFont.pointSize();
if (size == -1)
size = TQFontInfo(selFont).pointSize();
TQString sizeStr = TQString::number(size);
int numEntries, i;
numEntries = familyListBox->count();
for (i = 0; i < numEntries; i++)
{
if (family == familyListBox->text(i).lower())
{
familyListBox->setCurrentItem(i);
break;
}
}
// 1st Fallback
if ( (i == numEntries) )
{
if (family.contains('['))
{
family = family.left(family.find('[')).stripWhiteSpace();
for (i = 0; i < numEntries; i++)
{
if (family == familyListBox->text(i).lower())
{
familyListBox->setCurrentItem(i);
break;
}
}
}
}
// 2nd Fallback
if ( (i == numEntries) )
{
TQString fallback = family+" [";
for (i = 0; i < numEntries; i++)
{
if (familyListBox->text(i).lower().startsWith(fallback))
{
familyListBox->setCurrentItem(i);
break;
}
}
}
// 3rd Fallback
if ( (i == numEntries) )
{
for (i = 0; i < numEntries; i++)
{
if (familyListBox->text(i).lower().startsWith(family))
{
familyListBox->setCurrentItem(i);
break;
}
}
}
// Fall back in case nothing matched. Otherwise, diff doesn't work
if ( i == numEntries )
familyListBox->setCurrentItem( 0 );
styleListBox->setCurrentItem(style);
numEntries = sizeListBox->count();
for (i = 0; i < numEntries; i++)
{
if (sizeStr == sizeListBox->text(i))
{
sizeListBox->setCurrentItem(i);
break;
}
}
sizeOfFont->setValue(size);
}
void FontChooserWidget::getFontList( TQStringList &list, uint fontListCriteria)
{
TQFontDatabase dbase;
TQStringList lstSys(dbase.families());
// if we have criteria; then check fonts before adding
if (fontListCriteria)
{
TQStringList lstFonts;
TQStringList::Iterator end(lstSys.end());
for (TQStringList::Iterator it = lstSys.begin(); it != end; ++it)
{
if ((fontListCriteria & FixedWidthFonts) > 0 && !dbase.isFixedPitch(*it)) continue;
if (((fontListCriteria & (SmoothScalableFonts | ScalableFonts)) == ScalableFonts) &&
!dbase.isBitmapScalable(*it)) continue;
if ((fontListCriteria & SmoothScalableFonts) > 0 && !dbase.isSmoothlyScalable(*it)) continue;
lstFonts.append(*it);
}
if((fontListCriteria & FixedWidthFonts) > 0) {
// Fallback.. if there are no fixed fonts found, it is probably a
// bug in the font server or TQt. In this case, just use 'fixed'
if (lstFonts.count() == 0)
lstFonts.append("fixed");
}
lstSys = lstFonts;
}
lstSys.sort();
list = lstSys;
}
void FontChooserWidget::addFont( TQStringList &list, const char *xfont )
{
const char *ptr = strchr( xfont, '-' );
if ( !ptr )
return;
ptr = strchr( ptr + 1, '-' );
if ( !ptr )
return;
TQString font = TQString::fromLatin1(ptr + 1);
int pos;
if ( ( pos = font.find( '-' ) ) > 0 ) {
font.truncate( pos );
if ( font.find( TQString::fromLatin1("open look"), 0, false ) >= 0 )
return;
TQStringList::Iterator it = list.begin();
TQStringList::Iterator end(list.end());
for ( ; it != end; ++it )
if ( *it == font )
return;
list.append( font );
}
}
void FontChooserWidget::fillFamilyListBox(bool onlyFixedFonts)
{
TQStringList fontList;
getFontList(fontList, onlyFixedFonts?FixedWidthFonts:0);
familyListBox->clear();
familyListBox->insertStringList(fontList);
}
void FontChooserWidget::showXLFDArea(bool show)
{
if( show )
{
xlfdEdit->parentWidget()->show();
}
else
{
xlfdEdit->parentWidget()->hide();
}
}
} // NameSpace DigikamInsertTextImagesPlugin