1 // Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
24 // Author: Sergey TELKOV
38 #include <QApplication>
39 #include <QDesktopWidget>
47 #define BICOLOR_CHANGE_HUE
50 \brief Auxiliary function converting string \a str to the integer value.
51 Parameter \a defVal specifies default value that is returned if conversion can't be done.
52 Parameters \a minVal and \a maxVal limit the resulting value.
53 \param str string being converted
54 \param defVal default value
55 \param minVal minimum allowed value
56 \param maxVal maximum allowed value
57 \return integer value obtained from the string
60 static int stringToInt( const QString& str, int defVal, int minVal, int maxVal )
63 int v = str.toInt( &ok );
64 if ( !ok ) v = defVal;
65 return qMin( qMax( v, minVal ), maxVal );
70 \brief A set of helpful utility functions.
72 The class implements a set of the static functions which can be used
73 for the different purposes:
74 - specify tab order for the set of widgets: setTabOrder()
75 - align one widget to the coordinates of the another one: alignWidget()
76 - remove extra separators from the menu or toolbar: simplifySeparators()
77 - retrieve directory, file name and extension parts of the path:
78 dir(), file(), extension()
79 - get the path to the temporary directory: tmpDir()
80 - create or remove a directory (recursively): mkDir(), rmDir()
81 - convert text file from DOS to UNIX native format: dos2unix()
82 - convert a picture to the gray scale: grayscale()
87 \brief Convert character array (ASCII string) to the QString.
88 \param str character array
89 \param len array length, if < 0, the array should be zero-terminated
90 \return QString object
92 QString Qtx::toQString( const char* str, const int len )
94 return toQString( (unsigned char*)str, len );
98 \brief Convert integer array (UNICODE string) to the QString.
99 \param str integer array
100 \param len array length, if < 0, the array should be zero-terminated
101 \return QString object
103 QString Qtx::toQString( const short* str, const int len )
105 return toQString( (unsigned short*)str, len );
109 \brief Convert character array (ASCII string) to the QString.
110 \param str character array
111 \param len array length, if < 0, the array should be zero-terminated
112 \return QString object
114 QString Qtx::toQString( const unsigned char* str, const int len )
117 const unsigned char* s = str;
118 while ( len < 0 || res.length() < len )
123 res.append( QChar( *s ) );
130 \brief Convert integer array (UNICODE string) to the QString.
131 \param str integer array
132 \param len array length, if < 0, the array should be zero-terminated
133 \return QString object
135 QString Qtx::toQString( const unsigned short* str, const int len )
138 const unsigned short* s = str;
139 while ( len < 0 || res.length() < len )
144 res.append( QChar( *s ) );
151 \brief Set tab order for specified list of widgets.
153 The function has arbitrary number of parameters, each should be
154 hovewer of QWidget* type. Last parameter should be null pointer.
156 \param first first widget in the sequence
158 void Qtx::setTabOrder( QWidget* first, ... )
161 va_start( wids, first );
165 QWidget* cur = first;
168 widList.append( cur );
169 cur = va_arg( wids, QWidget* );
172 setTabOrder( widList );
176 \brief Set tab order for specified list of widgets.
177 \param widgets list of widgets
179 void Qtx::setTabOrder( const QWidgetList& widgets )
181 if ( widgets.count() < 2 )
185 for ( QWidgetList::const_iterator it = widgets.begin(); it!= widgets.end(); ++it )
189 QWidget::setTabOrder( prev, next );
195 \brief Align widget \a src relative to widget \a ref acording to the
196 alignment flags \a alignFlags.
197 \param src source widget (being aligned)
198 \param ref reference widget (source widget being aligned to)
199 \param alignFlags alignment flags (Qtx::AlignmentFlags)
201 void Qtx::alignWidget( QWidget* src, const QWidget* ref, const int alignFlags )
203 if ( !src || !ref || !alignFlags )
206 QPoint srcOri = src->pos();
207 QPoint refOri = ref->pos();
208 if ( src->parentWidget() && !src->isTopLevel() )
209 srcOri = src->parentWidget()->mapToGlobal( srcOri );
210 if ( ref->parentWidget() && !ref->isTopLevel() )
211 refOri = ref->parentWidget()->mapToGlobal( refOri );
213 int x = srcOri.x(), y = srcOri.y();
214 int refWidth = ref->frameGeometry().width(), refHei = ref->frameGeometry().height();
215 int srcWidth = src->frameGeometry().width(), srcHei = src->frameGeometry().height();
218 srcWidth = src->sizeHint().width();
220 srcHei = src->sizeHint().height();
223 if ( ref->isTopLevel() && ref->isMaximized() &&
224 src->isTopLevel() && !src->isMaximized() )
225 border = ( src->frameGeometry().width() - src->width() ) / 2;
227 if ( alignFlags & Qtx::AlignLeft )
228 x = refOri.x() + border;
229 if ( alignFlags & Qtx::AlignOutLeft )
230 x = refOri.x() - srcWidth - border;
231 if ( alignFlags & Qtx::AlignRight )
232 x = refOri.x() + refWidth - srcWidth - border;
233 if ( alignFlags & Qtx::AlignOutRight )
234 x = refOri.x() + refWidth + border;
235 if ( alignFlags & Qtx::AlignTop )
236 y = refOri.y() + border;
237 if ( alignFlags & Qtx::AlignOutTop )
238 y = refOri.y() - srcHei - border;
239 if ( alignFlags & Qtx::AlignBottom )
240 y = refOri.y() + refHei - srcHei - border;
241 if ( alignFlags & Qtx::AlignOutBottom )
242 y = refOri.y() + refHei + border;
243 if ( alignFlags & Qtx::AlignHCenter )
244 x = refOri.x() + ( refWidth - srcWidth ) / 2;
245 if ( alignFlags & Qtx::AlignVCenter )
246 y = refOri.y() + ( refHei - srcHei ) / 2;
248 if ( src->parentWidget() && !src->isTopLevel() )
250 QPoint pos = src->parentWidget()->mapFromGlobal( QPoint( x, y ) );
255 QWidget* desk = QApplication::desktop();
256 if ( desk && x + srcWidth + border > desk->width() )
257 x = desk->width() - srcWidth - border;
258 if ( desk && y + srcHei + border > desk->height() )
259 y = desk->height() - srcHei - border;
268 \brief Remove (recursively) unnecessary separators from the menu or toolbar.
269 \param wid widget, should be of QMenu* or QToolBar* class
271 void Qtx::simplifySeparators( QWidget* wid, const bool recursive )
276 QList<QAction*> items = wid->actions();
277 if ( items.isEmpty() )
280 QList<QAction*> toRemove;
281 for ( int i = 1; i < items.count(); i++ )
283 if ( items[i]->isSeparator() && items[i - 1]->isSeparator() )
284 toRemove.append( items[i] );
286 if ( recursive && items[i]->menu() )
287 simplifySeparators( items[i]->menu(), recursive );
290 for ( QList<QAction*>::iterator it = toRemove.begin(); it != toRemove.end(); ++it )
291 wid->removeAction( *it );
293 items = wid->actions();
294 if ( !items.isEmpty() && items[0]->isSeparator() )
295 wid->removeAction( items[0] );
297 items = wid->actions();
298 if ( !items.isEmpty() && items[items.count() - 1]->isSeparator() )
299 wid->removeAction( items[items.count() - 1] );
303 \brief Return \c true if specified \a parent is a parent object
304 of given \a child (in terms of QObject).
306 This function works recursively. It means that \a true is also
307 returned if \a parent is a grand-father, grand-grand-father, etc
308 of \a child. If the same object is given as both \a parent and
309 \a child, \c true is also returned.
311 \param child child object
312 \param parent parent object
313 \return \c true if the \a parent is a parent of \a child
315 bool Qtx::isParent( QObject* child, QObject* parent )
317 if ( !child || !parent )
321 QObject* obj = child;
322 while ( !res && obj )
331 \brief Find the parent object of class specified by \a className (in terms of QObject).
333 \param obj current object
334 \param className class name of the parent
335 \return parent object or null pointer if the parent not found
337 QObject* Qtx::findParent( QObject* obj, const char* className )
342 if ( !className || !strlen( className ) )
343 return obj->parent();
346 QObject* p = obj->parent();
349 if ( p->inherits( className ) )
358 \brief Return directory part of the file path.
360 If the file path does not include directory part (the file is in the
361 current directory), null string is returned.
363 \param path file path
364 \param abs if true (default) \a path parameter is treated as absolute file path
365 \return directory part of the file path
367 QString Qtx::dir( const QString& path, const bool abs )
369 QDir aDir = QFileInfo( path ).dir();
370 QString dirPath = abs ? aDir.absolutePath() : aDir.path();
371 if ( dirPath == QString( "." ) )
377 \brief Return file name part of the file path.
379 \param path file path
380 \param withExt if true (default) complete file name (with all
381 extension except the last) is returned, otherwise only base name
383 \return file name part of the file path
385 QString Qtx::file( const QString& path, bool withExt )
387 QString fPath = path;
388 while ( !fPath.isEmpty() && ( fPath[fPath.length() - 1] == '\\' || fPath[fPath.length() - 1] == '/' ) )
389 fPath.remove( fPath.length() - 1, 1 );
392 return QFileInfo( fPath ).fileName();
394 return QFileInfo( fPath ).completeBaseName();
398 \brief Return extension part of the file path.
400 \param path file path
401 \param full if true complete extension (all extensions, dot separated)
402 is returned, otherwise (default) only last extension is returned
403 \return extension part of the file path
405 QString Qtx::extension( const QString& path, const bool full )
407 return full ? QFileInfo( path ).completeSuffix() : QFileInfo( path ).suffix();
411 \brief Convert the given parameter to the platform-specific library name.
413 The function appends platform-specific prefix (lib) and suffix (.dll/.so)
414 to the library file name.
415 For example, if \a str = "mylib", "libmylib.so" is returned for Linux and
416 mylib.dll for Windows.
418 \param str short library name
419 \return full library name
421 QString Qtx::library( const QString& str )
423 QString path = dir( str, false );
424 QString name = file( str, false );
425 QString ext = extension( str );
428 if ( !name.startsWith( "lib" ) )
429 name = QString( "lib" ) + name;
433 QString libExt( "dll" );
435 QString libExt( "so" );
438 if ( ext.toLower() != QString( "so" ) && ext.toLower() != QString( "dll" ) )
440 if ( !name.isEmpty() && !ext.isEmpty() )
441 name += QString( "." );
447 QString fileName = addSlash( path ) + name + QString( "." ) + ext;
453 \brief Get the temporary directory name.
454 \return temporary directory (platform specific)
456 QString Qtx::tmpDir()
458 const char* tmpdir = ::getenv( "TEMP" );
460 tmpdir = ::getenv ( "TMP" );
469 return QString( tmpdir );
473 \brief Create directory recursively including all intermediate sub directories.
474 \return \c true if the directory is successfully created and \c false otherwise
476 bool Qtx::mkDir( const QString& dirPath )
478 return QDir().mkpath( dirPath );
482 \brief Remove directory recursively including all subdirectories and files.
483 \return \c true if the directory is successfully removed and \c false otherwise
485 bool Qtx::rmDir( const QString& thePath )
487 QFileInfo fi( thePath );
493 stat = QFile::remove( thePath );
494 else if ( fi.isDir() )
496 QDir aDir( thePath );
497 QFileInfoList anEntries = aDir.entryInfoList();
498 for ( QFileInfoList::iterator it = anEntries.begin(); it != anEntries.end(); ++it )
501 if ( inf.fileName() == "." || inf.fileName() == ".." )
503 stat = stat && rmDir( inf.absoluteFilePath() );
505 stat = stat && aDir.rmdir( thePath );
511 \brief Add a slash (platform-specific) to the end of \a path
512 if it is not already there.
513 \param path directory path
514 \return modified path (with slash added to the end)
516 QString Qtx::addSlash( const QString& path )
519 if ( !res.isEmpty() && res.at( res.length() - 1 ) != QChar( '/' ) &&
520 res.at( res.length() - 1 ) != QChar( '\\' ) )
521 res += QDir::separator();
526 \brief Convert text file from DOS format to UNIX.
528 The function replaces "LF/CR" symbols sequence by "LF" symbol.
530 \param absName file name
531 \return \c true if the file is converted successfully and \c false in
534 bool Qtx::dos2unix( const QString& absName )
536 FILE* src = ::fopen( absName.toLatin1(), "rb" );
540 /* we'll use temporary file */
541 char temp[512] = { '\0' };
542 QString dir = Qtx::dir( absName );
543 FILE* tgt = ::fopen( strcpy( temp, ::tempnam( dir.toLatin1(), "__x" ) ), "wb" );
547 /* temp -> result of conversion */
548 const char CR = 0x0d;
549 const char LF = 0x0a;
550 bool waitingLF = false;
555 char inbuf[512], outbuf[512];
558 int nbread = ::fread( inbuf, 1, sizeof( inbuf ), src );
559 for ( int incnt = 0; incnt < nbread; incnt++ )
564 if ( inbuf[incnt] == LF )
565 outbuf[outcnt++] = LF;
567 outbuf[outcnt++] = CR;
569 else if ( inbuf[incnt] == CR )
572 outbuf[outcnt++] = inbuf[incnt];
575 /* check last sym in buffer */
576 waitingLF = ( inbuf[nbread - 1] == CR );
578 /* write converted buffer to temp file */
579 int nbwri = ::fwrite( outbuf, 1, outcnt, tgt );
580 if ( nbwri != outcnt )
584 QFile::remove( QString( temp ) );
587 if ( nbread != sizeof( inbuf ) )
588 break; /* converted ok */
593 /* rename temp -> src */
594 if ( !QFile::remove( absName ) )
597 return QDir().rename( QString( temp ), absName );
601 \brief Create path completer which can be used in the widgets
602 to provide auto completions.
604 Create an instance of QCompleter class and returns the pointer on it.
605 The calling function is responsible to the desstroying of the created
608 The QCompleter class provides completions based on a item model and can be
609 used in such as QLineEdit and QComboBox.
610 When the user starts typing a word, QCompleter suggests possible ways of
611 completing the word, based on a word list.
613 \param type path type (Qtx::PathType)
614 \param filter file/directory filters (list of wildcards, separated by ";;")
615 \return a pointer to the created completer
617 QCompleter* Qtx::pathCompleter( const PathType type, const QString& filter )
620 QStringList filterList = filter.split( ";;" );
621 for ( QStringList::const_iterator it = filterList.begin(); it != filterList.end(); ++it )
623 QRegExp rx( "[\\s\\w,;]*\\(?\\*\\.([\\w]+)\\)?[\\d\\s\\w]*" );
625 while ( ( index = rx.indexIn( *it, index ) ) != -1 )
627 extList.append( QString( "*.%1" ).arg( rx.cap( 1 ) ) );
628 index += rx.matchedLength();
632 QDir::Filters filters = 0;
637 filters = QDir::AllEntries | QDir::AllDirs | QDir::NoDotAndDotDot;
640 filters = QDir::Drives | QDir::Dirs | QDir::NoDotAndDotDot;
644 QDirModel* dm = new QDirModel( extList, filters, QDir::Unsorted );
645 QCompleter* cmp = new QCompleter( dm, 0 );
646 dm->setParent( cmp );
652 \brief Parse given string to retrieve environment variable.
654 Looks through the string for the environment variable patterns.
655 If string contains variable satisfying any pattern, the variable name
656 is returned, start index of the variable is returned in the \a start parameter,
657 and length of the variable is returned in the \a len parameter.
659 Supported environment variables definitions:
660 - ${name} or $name : Linux shell variable
661 - $(name) : GNU make substitution
662 - %name% : Windows shell variable
663 - %(name)s : Python substitutions:
665 \param str string being processed
666 \param start if variable is found, this parameter contains its starting
667 position in the \a str
668 \param len if variable is found, this parameter contains its length
669 \return first found variable or null QString if there is no ones
671 QString Qtx::findEnvVar( const QString& str, int& start, int& len )
677 rxList << "\\$\\{([a-zA-Z][a-zA-Z_0-9]*)\\}"; // ${name}
678 rxList << "\\$([a-zA-Z][a-zA-Z_0-9]*)"; // $name
679 rxList << "\\$\\(([a-zA-Z][a-zA-Z_0-9]*)\\)"; // $(name)
680 rxList << "%([a-zA-Z][a-zA-Z0-9_]*)%"; // %name%
681 rxList << "%\\(([a-zA-Z][a-zA-Z_0-9]*)\\)s"; // %(name)s
683 for ( int i = 0; i < rxList.count() && varName.isEmpty(); ++i )
685 QRegExp rx(rxList[i]);
686 int pos = rx.indexIn( str, start );
689 varName = rx.cap( 1 );
691 len = rx.matchedLength();
698 \brief Substitute environment variables by their values.
700 Environment variable is substituted by its value.
702 \param str string to be processed
703 \return processed string (with all substitutions made)
705 QString Qtx::makeEnvVarSubst( const QString& str, const SubstMode mode )
710 QMap<QString, int> ignoreMap;
712 int start( 0 ), len( 0 );
715 QString envName = findEnvVar( res, start, len );
716 if ( envName.isNull() )
720 if ( ::getenv( envName.toLatin1() ) || mode == Always )
721 newStr = QString( ::getenv( envName.toLatin1() ) );
723 if ( newStr.isNull() )
725 if ( ignoreMap.contains( envName ) )
730 ignoreMap.insert( envName, 0 );
732 res.replace( start, len, newStr );
735 res.replace( "$$", "$" );
736 res.replace( "%%", "%" );
743 \brief Pack the specified color into integer RGB set.
744 \param c unpacked color
747 int Qtx::rgbSet( const QColor& c )
749 return rgbSet( c.red(), c.green(), c.blue() );
753 \brief Pack the specified RGB color components into integer RGB set.
754 \param r red component
755 \param g green component
756 \param b blue component
759 int Qtx::rgbSet( const int r, const int g, const int b )
761 return ( ( ( 0xff & r ) << 16 ) + ( ( 0xff & g ) << 8 ) + ( 0xff & b ) );
765 \brief Unpack the specified integer RGB set to the color.
766 \param rgb packed color
767 \return unpacked color (QColor)
769 QColor Qtx::rgbSet( const int rgb )
772 rgbSet( rgb, r, g, b );
773 return QColor( r, g, b );
777 \brief Unpack the specified integer RGB set to the three RGB components.
778 \param rgb packed color
779 \param r returned unpacked red component
780 \param g returned unpacked green component
781 \param b returned unpacked blue component
783 void Qtx::rgbSet( const int rgb, int& r, int& g, int& b )
785 r = ( rgb >> 16 ) & 0xff;
786 g = ( rgb >> 8 ) & 0xff;
791 \brief Return the color specified by the index between min (blue) and max (red).
792 \param index color index
793 \param min required minimum hue value
794 \param max required maximum hue value
795 \return resulting color
797 QColor Qtx::scaleColor( const int index, const int min, const int max )
799 static const int HUE[10] = {230, 210, 195, 180, 160, 80, 60, 50, 30, 0};
805 double aPosition = 9.0 * ( index - min ) / ( max - min );
806 if ( aPosition > 0.0 )
808 if ( aPosition >= 9.0 )
812 int idx = (int)aPosition;
813 hue = HUE[idx] + int( ( aPosition - idx ) * ( HUE[idx + 1] - HUE[idx] ) );
818 return QColor::fromHsv( hue, 255, 255 );
822 \brief Generate required number of colors aligned from blue to red.
823 \param num required number of colors
824 \param lst returned set of colors
826 void Qtx::scaleColors( const int num, QColorList& lst )
829 for ( int i = 0; i < num; i++ )
830 lst.append( scaleColor( i, 0, num - 1 ) );
834 \brief Scale the pixmap to the required size.
836 If \a h is 0 (default) the value of \a w is used instead (to create
839 \param icon pixmap to be resized
840 \param w required pixmap width
841 \param h required pixmap height
842 \return scaled pixmap
844 QPixmap Qtx::scaleIcon( const QPixmap& icon, const unsigned w, const unsigned h )
847 int aw = w, ah = h <= 0 ? w : h;
848 if ( icon.isNull() || aw <= 0 || ah <= 0 || ( aw == icon.width() && ah == icon.height() ) )
851 p = icon.fromImage( icon.toImage().scaled( aw, ah, Qt::KeepAspectRatio, Qt::SmoothTransformation ) );
856 \brief Convert given image to the grayscale format.
857 \param img initial image
858 \return converted to the grayscale image
860 QImage Qtx::grayscale( const QImage& img )
864 int colNum = res.colorCount();
867 for ( int i = 0; i < colNum; i++ )
868 res.setColor( i, qGray( res.color( i ) ) );
872 for ( int y = 0; y < res.height(); y++ )
874 for ( int x = 0; x < res.width(); x++ )
876 QRgb pix = res.pixel( x, y );
877 res.setPixel( x, y, qRgba( qGray( pix ), qGray( pix ), qGray( pix ), qAlpha( pix ) ) );
886 \brief Convert given pixmap to the grayscale format.
887 \param pix initial pixmap
888 \return converted to the grayscale pixmap
890 QPixmap Qtx::grayscale( const QPixmap& pix )
893 res.fromImage( grayscale( pix.toImage() ) );
898 \brief Create transparent image.
899 \param w required image width
900 \param h required image height
901 \param d required image depth
902 \return generated image
904 QImage Qtx::transparentImage( const int w, const int h, const int d )
910 fmt = QImage::Format_Mono;
913 fmt = QImage::Format_Indexed8;
919 fmt = QImage::Format_ARGB32;
923 QImage img( w, h, fmt );
926 // img.setAlphaBuffer( true );
927 for ( int i = 0; i < img.height(); i++ )
928 for ( int j = 0; j < img.width(); j++ )
929 img.setPixel( j, i, qRgba( 0, 0, 0, 0 ) );
935 \brief Create transparent pixmap.
936 \param w required image width
937 \param h required pixmap height
938 \param d required pixmap depth
939 \return generated pixmap
941 QPixmap Qtx::transparentPixmap( const int w, const int h, const int d )
944 QImage img = transparentImage( w, h, d );
946 pix.fromImage( img );
951 \brief Create composite pixmap.
953 Pixmap \a pix is drawn over pixmap \a dest with coordinates
954 specified relatively to the upper left corner of \a dest.
955 If \a dest is not given, the new empty pixmap with appropriate size created instead.
957 \param pix source pixmap
958 \param x horizontal shift
959 \param y vertical shift
960 \param dest background pixmap
961 \return resulting pixmap
963 QPixmap Qtx::composite( const QPixmap& pix, const int x, const int y, const QPixmap& dest )
968 int width = qMax( pix.width() + x, dest.width() );
969 int height = qMax( pix.height() + y, dest.height() );
971 QPixmap res( width, height );
972 QImage img = transparentImage( width, height, 32 );
976 p.fillRect( 0, 0, width, height, QBrush( Qt::white ) );
978 if ( !dest.isNull() )
980 p.drawPixmap( 0, 0, dest );
981 QImage temp = dest.toImage();
982 for ( int i = 0; i < temp.width() && i < img.width(); i++ )
984 for ( int j = 0; j < temp.height() && j < img.height(); j++ )
986 if ( temp.hasAlphaChannel() )
987 img.setPixel( i, j, temp.pixel( i, j ) );
990 QRgb p = temp.pixel( i, j );
991 img.setPixel( i, j, qRgba( qRed( p ), qGreen( p ), qBlue( p ), 255 ) );
997 p.drawPixmap( x, y, pix );
998 QImage temp = pix.toImage();
999 for ( int c = x; c < temp.width() + x && c < img.width(); c++ )
1001 for ( int r = y; r < temp.height() + y && r < img.height(); r++ )
1003 if ( qAlpha( temp.pixel( c - x, r - y ) ) > 0 )
1004 img.setPixel( c, r, temp.pixel( c - x, r - y ) );
1010 for ( int ai = 0; ai < img.width(); ai++ )
1012 for ( int aj = 0; aj < img.height(); aj++ )
1014 if ( qAlpha( img.pixel( ai, aj ) ) < 1 )
1015 img.setPixel( ai, aj, qRgba( 255, 255, 255, 255 ) );
1017 img.setPixel( ai, aj, qRgba( 0, 0, 0, 0 ) );
1021 QBitmap bmp( width, height );
1022 bmp.fromImage( img, Qt::ColorMode_Mask | Qt::ThresholdDither );
1029 \brief Convert color to the string representation.
1031 The resulting string is in the one of two possible formats
1032 (\c RR, \c GG, \c BB and \c AA value represent red, green, blue
1033 and alpha components of the color):
1034 - if color has alpha channel : "#RR,#GG,#BB,#AA"
1035 - if color does not have alpha channel : "#RRGGBB"
1037 If color is invalid, null string is returned.
1039 Backward conversion can be done with stringToColor() method.
1041 \param color color to be converted
1042 \return string representation of the color
1046 QString Qtx::colorToString( const QColor& color )
1049 if ( color.isValid() )
1051 if ( color.alpha() != 255 )
1054 vals << QString( "#%1" ).arg( color.red(), 0, 16 );
1055 vals << QString( "#%1" ).arg( color.green(), 0, 16 );
1056 vals << QString( "#%1" ).arg( color.blue(), 0, 16 );
1057 vals << QString( "#%1" ).arg( color.alpha(), 0, 16 );
1058 str = vals.join( "," );
1069 \brief Create color from the string representation.
1071 The parameter \a str must be in the one of following formats
1072 (\c RR, \c GG, \c BB and \c AA value represent red, green, blue
1073 and alpha components of the color):
1074 - "#RR,#GG,#BB[,#AA]" or "#RR #GG #BB[ #AA]" (\c RR, \c GG, \c BB
1075 and optional \c AA values represent red, green, blue and alpha
1076 components of the color in hexadecimal form)
1077 - "RR,GG,BB[,AA]" or "RR GG BB[ AA]" (\c RR, \c GG, \c BB
1078 and optional \c AA values represent red, green, blue and alpha
1079 components of the color in decimal form)
1080 - "#RRGGBB" - (\c RR, \c GG and \c BB values represent red, green and blue
1081 components of the color in hexadecimal form)
1082 - an integer value representing packed color components (see rgbSet())
1083 - a name from the list of colors defined in the list of SVG color keyword names
1084 provided by the World Wide Web Consortium; for example, "steelblue" or "gainsboro".
1086 Backward conversion can be done with colorToString() method.
1088 \param str string representation of the color
1089 \param color resulting color value
1090 \return \c true if the conversion is successful and \c false otherwise
1092 \sa colorToString(), rgbSet()
1094 bool Qtx::stringToColor( const QString& str, QColor& color )
1097 QStringList vals = str.split( QRegExp( "[\\s|,]" ), QString::SkipEmptyParts );
1100 for ( QStringList::const_iterator it = vals.begin(); it != vals.end() && res; ++it )
1103 if ( (*it).startsWith( "#" ) )
1104 num = (*it).mid( 1 ).toInt( &res, 16 );
1106 num = (*it).toInt( &res, 10 );
1111 res = res && nums.count() >= 3;
1113 color.setRgb( nums[0], nums[1], nums[2] );
1117 int pack = str.toInt( &res );
1119 color = Qtx::rgbSet( pack );
1124 color = QColor( str );
1125 res = color.isValid();
1132 \brief Convert bi-color value to the string representation.
1134 Bi-color value is specified as main color and integer delta
1135 value that is used to calculate secondary color by changing
1136 paremeters of the main color ("saturation" and "value"
1137 components in HSV notation).
1139 The resulting string consists of two sub-strings separated by
1140 '|' symbol. The first part represents main color
1141 (see colorToString() for more details), the second part is a
1144 Backward conversion can be done with stringToBiColor() method.
1146 \param color color to be converted
1147 \param delta delta value
1148 \return string representation of the bi-color value
1150 \sa stringToBiColor(), stringToColor()
1152 QString Qtx::biColorToString( const QColor& color, const int delta )
1154 return QString("%1|%2").arg( Qtx::colorToString( color ) ).arg( delta );
1158 \brief Restore bi-color value from the string representation.
1160 Bi-color value is specified as main color and integer delta
1161 value that is used to calculate secondary color by changing
1162 paremeters of the main color ("saturation" and "value"
1163 components in HSV notation).
1165 The parameter \a str should consist of two sub-strings separated
1166 by '|' symbol. The first part represents main color
1167 (see stringToColor() for more details), the second part is a
1170 Backward conversion can be done with biColorToString() method.
1172 \param str string representation of the bi-color value
1173 \param color resulting color value
1174 \param delta resulting delta value
1175 \return \c true if the conversion is successful and \c false otherwise
1177 \sa biColorToString(), stringToColor(), rgbSet()
1179 bool Qtx::stringToBiColor( const QString& str, QColor& color, int& delta )
1181 QStringList data = str.split( "|", QString::KeepEmptyParts );
1184 bool ok = data.count() > 0 && Qtx::stringToColor( data[0], c );
1186 if ( data.count() > 1 ) d = data[1].toInt( &dok );
1188 color = ok ? c : QColor();
1194 \brief Compute secondary color value from specified main color
1197 Secondary color is calculated by changing paremeters of the main
1198 color ("saturation" and "value" components in HSV notation) using
1201 If main color is invalid, result of the function is also invalid color.
1203 \param color source main color
1204 \param delta delta value
1205 \return resulting secondary color
1207 \sa biColorToString(), stringToBiColor()
1209 QColor Qtx::mainColorToSecondary( const QColor& color, int delta )
1212 if ( cs.isValid() ) {
1213 int val = qMin( 255, qMax( cs.value() + delta, 0 ) );
1214 int sat = qMin( 255, qMax( cs.saturation() + delta-(val-cs.value()), 0 ) );
1215 #ifdef BICOLOR_CHANGE_HUE
1216 const int BICOLOR_HUE_MAXDELTA = 40;
1217 int dh = delta-(val-cs.value())-(sat-cs.saturation());
1218 dh = qMin( BICOLOR_HUE_MAXDELTA, qAbs( dh ) ) * ( dh > 0 ? 1 : -1 );
1219 //int hue = qMin( 359, qMax( cs.hue() + delta-(val-cs.value())-(sat-cs.saturation()), 0 ) );
1220 //int hue = qMin( 359, qMax( cs.hue() + delta-(val-cs.value())-ds, 0 ) );
1221 int hue = cs.hue() + dh;
1222 if ( hue < 0 ) hue = 360 - hue;
1226 cs.setHsv( hue, sat, val );
1232 \brief Dump linear gradient to the string description.
1233 \param gradient linear gradient to be converted
1234 \return string representation of the linear gradient
1235 \sa stringToLinearGradient()
1237 QString Qtx::gradientToString( const QLinearGradient& gradient )
1241 data << QString::number( gradient.start().x() );
1242 data << QString::number( gradient.start().y() );
1243 data << QString::number( gradient.finalStop().x() );
1244 data << QString::number( gradient.finalStop().y() );
1245 switch( gradient.spread() )
1247 case QGradient::PadSpread:
1250 case QGradient::RepeatSpread:
1253 case QGradient::ReflectSpread:
1259 QGradientStops stops = gradient.stops();
1261 foreach ( stop, stops )
1263 data << QString::number( stop.first );
1264 data << colorToString( stop.second );
1266 return data.join( "|" );
1270 \brief Dump radial gradient to the string description.
1271 \param gradient radial gradient to be converted
1272 \return string representation of the radial gradient
1273 \sa stringToRadialGradient()
1275 QString Qtx::gradientToString( const QRadialGradient& gradient )
1279 data << QString::number( gradient.center().x() );
1280 data << QString::number( gradient.center().y() );
1281 data << QString::number( gradient.focalPoint().x() );
1282 data << QString::number( gradient.focalPoint().y() );
1283 data << QString::number( gradient.radius() );
1284 switch( gradient.spread() )
1286 case QGradient::PadSpread:
1289 case QGradient::RepeatSpread:
1292 case QGradient::ReflectSpread:
1298 QGradientStops stops = gradient.stops();
1300 foreach ( stop, stops )
1302 data << QString::number( stop.first );
1303 data << colorToString( stop.second );
1305 return data.join( "|" );
1309 \brief Dump conical gradient to the string description.
1310 \param gradient conical gradient to be converted
1311 \return string representation of the conical gradient
1312 \sa stringToConicalGradient()
1314 QString Qtx::gradientToString( const QConicalGradient& gradient )
1318 data << QString::number( gradient.center().x() );
1319 data << QString::number( gradient.center().y() );
1320 data << QString::number( gradient.angle() );
1321 switch( gradient.spread() )
1323 case QGradient::PadSpread:
1326 case QGradient::RepeatSpread:
1329 case QGradient::ReflectSpread:
1335 QGradientStops stops = gradient.stops();
1337 foreach ( stop, stops )
1339 data << QString::number( stop.first );
1340 data << colorToString( stop.second );
1342 return data.join( "|" );
1346 \brief Create linear gradient from its string representation.
1347 \param str string representation of the linear gradient
1348 \param gradient resulting linear gradient object
1349 \return \c true if the conversion is successful and \c false otherwise
1350 \sa gradientToString()
1352 bool Qtx::stringToLinearGradient( const QString& str, QLinearGradient& gradient )
1354 bool success = false;
1355 QStringList vals = str.split( "|", QString::SkipEmptyParts );
1356 if ( vals.count() > 4 && ( vals[0] == "linear" || vals[0] == "lg" ) )
1358 // start and end points
1359 double x1, y1, x2, y2;
1360 bool bOk1, bOk2, bOk3, bOk4;
1361 x1 = vals[1].toDouble( &bOk1 );
1362 y1 = vals[2].toDouble( &bOk2 );
1363 x2 = vals[3].toDouble( &bOk3 );
1364 y2 = vals[4].toDouble( &bOk4 );
1365 if ( bOk1 && bOk2 && bOk3 && bOk4 )
1367 gradient = QLinearGradient( x1, y1, x2, y2 );
1369 if ( vals.count() > 5 )
1371 QString spread = vals[ 5 ].trimmed().toLower();
1372 if ( spread == "pad" || spread == "0" )
1373 gradient.setSpread( QGradient::PadSpread );
1374 else if ( spread == "repeat" || spread == "2" )
1375 gradient.setSpread( QGradient::RepeatSpread );
1376 else if ( spread == "reflect" || spread == "1" )
1377 gradient.setSpread( QGradient::ReflectSpread );
1380 QGradientStops stops;
1381 for ( int i = 6; i < vals.count(); i+=2 )
1383 bool bOk5, bOk6 = false;
1385 double stop = vals[i].toDouble( &bOk5 );
1386 if ( i+1 < vals.count() )
1387 bOk6 = stringToColor( vals[ i+1 ], c );
1388 if ( bOk5 && stop >= 0.0 && stop <= 1.0 && bOk6 && c.isValid() )
1389 stops.append( QGradientStop( stop, c ) );
1391 gradient.setStops( stops );
1399 \brief Create radial gradient from its string representation.
1400 \param str string representation of the radial gradient
1401 \param gradient resulting radial gradient object
1402 \return \c true if the conversion is successful and \c false otherwise
1403 \sa gradientToString()
1405 bool Qtx::stringToRadialGradient( const QString& str, QRadialGradient& gradient )
1407 bool success = false;
1408 QStringList vals = str.split( "|", QString::SkipEmptyParts );
1409 if ( vals.count() > 5 && ( vals[0] == "radial" || vals[0] == "rg" ) )
1411 // center, radius and focal point
1412 double cx, cy, r, fx, fy;
1413 bool bOk1, bOk2, bOk3, bOk4, bOk5;
1414 cx = vals[1].toDouble( &bOk1 );
1415 cy = vals[2].toDouble( &bOk2 );
1416 fx = vals[3].toDouble( &bOk4 );
1417 fy = vals[4].toDouble( &bOk5 );
1418 r = vals[5].toDouble( &bOk3 );
1419 if ( bOk1 && bOk2 && bOk3 && bOk4 && bOk5 )
1421 gradient = QRadialGradient( cx, cy, r, fx, fy );
1423 if ( vals.count() > 6 )
1425 QString spread = vals[ 6 ].trimmed().toLower();
1426 if ( spread == "pad" || spread == "0" )
1427 gradient.setSpread( QGradient::PadSpread );
1428 else if ( spread == "repeat" || spread == "2" )
1429 gradient.setSpread( QGradient::RepeatSpread );
1430 else if ( spread == "reflect" || spread == "1" )
1431 gradient.setSpread( QGradient::ReflectSpread );
1434 QGradientStops stops;
1435 for ( int i = 7; i < vals.count(); i+=2 )
1437 bool bOk7, bOk8 = false;
1439 double stop = vals[i].toDouble( &bOk7 );
1440 if ( i+1 < vals.count() )
1441 bOk8 = stringToColor( vals[ i+1 ], c );
1442 if ( bOk7 && stop >= 0.0 && stop <= 1.0 && bOk8 && c.isValid() )
1443 stops.append( QGradientStop( stop, c ) );
1445 gradient.setStops( stops );
1453 \brief Create conical gradient from its string representation.
1454 \param str string representation of the conical gradient
1455 \param gradient resulting conical gradient object
1456 \return \c true if the conversion is successful and \c false otherwise
1457 \sa gradientToString()
1459 bool Qtx::stringToConicalGradient( const QString& str, QConicalGradient& gradient )
1461 bool success = false;
1462 QStringList vals = str.split( "|", QString::SkipEmptyParts );
1463 if ( vals.count() > 3 && ( vals[0] == "conical" || vals[0] == "cg" ) )
1467 bool bOk1, bOk2, bOk3;
1468 cx = vals[1].toDouble( &bOk1 );
1469 cy = vals[2].toDouble( &bOk2 );
1470 a = vals[3].toDouble( &bOk3 );
1471 if ( bOk1 && bOk2 && bOk3 )
1473 gradient = QConicalGradient( cx, cy, a );
1475 if ( vals.count() > 4 )
1477 QString spread = vals[ 4 ].trimmed().toLower();
1478 if ( spread == "pad" || spread == "0" )
1479 gradient.setSpread( QGradient::PadSpread );
1480 else if ( spread == "repeat" || spread == "2" )
1481 gradient.setSpread( QGradient::RepeatSpread );
1482 else if ( spread == "reflect" || spread == "1" )
1483 gradient.setSpread( QGradient::ReflectSpread );
1486 QGradientStops stops;
1487 for ( int i = 5; i < vals.count(); i+=2 )
1489 bool bOk4, bOk5 = false;
1491 double stop = vals[i].toDouble( &bOk4 );
1492 if ( i+1 < vals.count() )
1493 bOk5 = stringToColor( vals[ i+1 ], c );
1494 if ( bOk4 && stop >= 0.0 && stop <= 1.0 && bOk5 && c.isValid() )
1495 stops.append( QGradientStop( stop, c ) );
1497 gradient.setStops( stops );
1505 \brief Convert background data to the string representation.
1506 The resulting string consists of several sub-strings separated by ';' symbol.
1507 These sub-strings represent:
1508 1. background type (enumerator, see Qtx::BackgroundMode)
1509 2. texture image file name (string)
1510 3. texture mode (enumerator, see Qtx::TextureMode)
1511 4. "show texture" flag (boolean)
1512 5. first color (for simple gradient data) or solid color (for single-colored mode)
1513 6. second color (for simple gradient data)
1514 7. type of simple gradient (some integer identifier)
1515 8. complex gradient data (for custom gradient mode)
1516 Each sub-string consists of keyword/value couple, in form of "<keyword>=<value>".
1518 Backward conversion can be done with stringToBackground() method.
1520 \param bgData background data
1521 \return string representation of the background data
1523 \sa stringToBackground()
1525 QString Qtx::backgroundToString( const Qtx::BackgroundData& bgData )
1527 const QString dtSep = ";";
1528 const QString kwSep = "=";
1529 const QString kwBgType = "bt";
1530 const QString kwFileName = "fn";
1531 const QString kwTextureMode = "tm";
1532 const QString kwShowTexture = "ts";
1533 const QString kwFirstColor = "c1";
1534 const QString kwSecondColor = "c2";
1535 const QString kwGrType = "gt";
1536 const QString kwGrData = "gr";
1538 Qtx::BackgroundMode bgMode = bgData.mode();
1540 Qtx::TextureMode textureMode = bgData.texture( fileName );
1541 bool showTexture = bgData.isTextureShown();
1543 int gradientType = bgData.gradient( c1, c2 );
1544 const QGradient* gradient = bgData.gradient();
1547 switch ( gradient->type() ) {
1548 case QGradient::LinearGradient:
1549 grString = gradientToString( *(static_cast<const QLinearGradient*>( gradient )) );
1551 case QGradient::RadialGradient:
1552 grString = gradientToString( *(static_cast<const QRadialGradient*>( gradient )) );
1554 case QGradient::ConicalGradient:
1555 grString = gradientToString( *(static_cast<const QConicalGradient*>( gradient )) );
1562 data << QString( "%1%2%3" ).arg( kwBgType ).arg( kwSep ).arg( (int)bgMode );
1563 data << QString( "%1%2%3" ).arg( kwFileName ).arg( kwSep ).arg( fileName );
1564 data << QString( "%1%2%3" ).arg( kwTextureMode ).arg( kwSep ).arg( (int)textureMode );
1565 data << QString( "%1%2%3" ).arg( kwShowTexture ).arg( kwSep ).arg( showTexture ? "true" : "false" );
1566 data << QString( "%1%2%3" ).arg( kwFirstColor ).arg( kwSep ).arg( Qtx::colorToString( c1 ) );
1567 data << QString( "%1%2%3" ).arg( kwSecondColor ).arg( kwSep ).arg( Qtx::colorToString( c2 ) );
1568 data << QString( "%1%2%3" ).arg( kwGrType ).arg( kwSep ).arg( gradientType );
1569 data << QString( "%1%2%3" ).arg( kwGrData ).arg( kwSep ).arg( grString );
1571 return data.join( dtSep );
1575 \brief Restore background data from the string representation.
1577 The string should consist of several sub-strings separated by ';' symbol.
1578 Each sub-string consists of keyword/value couple, in form of "<keyword>=<value>".
1579 The sub-strings can follow in arbitrary order, some keywords can be missing.
1580 The background data is described by the following values:
1581 - background type (enumerator, see Qtx::BackgroundMode), keyword "bt"
1582 - texture image file name (string), keyword "fn"
1583 - texture mode (enumerator, see Qtx::TextureMode), keyword "tm"
1584 - "show texture" flag (boolean), keyword "ts"
1585 - first color (for simple gradient data) or solid color (for single-colored mode), keyword "c1"
1586 - second color (for simple gradient data), keyword "c2"
1587 - name of gradient type (string), keyword "gt"
1588 - complex gradient data (for custom gradient mode), keyword "gr"
1590 Also, for backward compatibility, background data can be represented by
1591 single color value, see stringToColor().
1593 Backward conversion can be done with backgroundToString() method.
1594 Returns invalid background if conversion could not be done.
1597 Qtx::BackgroundData bgData = Qtx::stringToBackground( str );
1598 if ( bgData.isValid() ) ) doSomething( bgData );
1601 \param theString string representation of the background data
1602 \return resulting background data (invalid if conversion has failed)
1604 \sa backgroundToString()
1607 Qtx::BackgroundData Qtx::stringToBackground( const QString& str )
1609 const QString dtSep = ";";
1610 const QString kwSep = "=";
1611 const QString kwBgType = "bt";
1612 const QString kwFileName = "fn";
1613 const QString kwTextureMode = "tm";
1614 const QString kwShowTexture = "ts";
1615 const QString kwFirstColor = "c1";
1616 const QString kwSecondColor = "c2";
1617 const QString kwGrType = "gt";
1618 const QString kwGrData = "gr";
1620 Qtx::BackgroundData bgData = BackgroundData();
1622 QStringList data = str.split( dtSep, QString::KeepEmptyParts );
1625 if ( data.count() == 1 && !data.contains( kwSep ) && stringToColor( data[0], c ) ) {
1626 // solid color mode, for backward compatibility
1627 bgData.setColor( c );
1630 QMap<QString, QString> dmap;
1632 foreach( QString d, data ) {
1633 QStringList items = d.split( kwSep, QString::KeepEmptyParts );
1634 if ( items.count() > 0 ) {
1635 QString kw = items.takeFirst().trimmed().toLower(); // keyword
1636 QString val = items.join( kwSep ).trimmed(); // if value contains "=" symbol, we have to restore it
1640 QString bgMode = dmap.value( kwBgType, QString() );
1641 QString fileName = dmap.value( kwFileName, QString() );
1642 QString textureMode = dmap.value( kwTextureMode, QString() );
1643 QString showTexture = dmap.value( kwShowTexture, QString() );
1644 QString color1 = dmap.value( kwFirstColor, QString() );
1645 QString color2 = dmap.value( kwSecondColor, QString() );
1646 QString gradientType = dmap.value( kwGrType, QString() );
1647 QString gradient = dmap.value( kwGrData, QString() );
1650 if ( !fileName.isEmpty() || !textureMode.isEmpty() || !showTexture.isEmpty() ) {
1651 Qtx::TextureMode m = (Qtx::TextureMode)( stringToInt( textureMode, Qtx::CenterTexture,
1652 Qtx::CenterTexture, Qtx::StretchTexture ) );
1653 bgData.setTexture( fileName, m );
1654 QStringList boolvars; boolvars << "true" << "yes" << "ok" << "1";
1655 if ( boolvars.contains( showTexture.trimmed().toLower() ) )
1656 bgData.setTextureShown( true );
1660 bool ok = Qtx::stringToColor( color1, c1 );
1662 bgData.setColor( c1 );
1664 // try simple gradient mode
1665 ok = Qtx::stringToColor( color2, c2 );
1666 if ( ok || !gradientType.isEmpty() ) {
1667 int gt = gradientType.toInt( &ok );
1668 bgData.setGradient( ok ? gt : -1, c1, c2 );
1670 // try custom gradient mode
1672 QConicalGradient cg;
1674 ok = Qtx::stringToLinearGradient( gradient, lg );
1676 bgData.setGradient( lg );
1678 ok = Qtx::stringToRadialGradient( gradient, rg );
1680 bgData.setGradient( rg );
1682 ok = Qtx::stringToConicalGradient( gradient, cg );
1684 bgData.setGradient( cg );
1687 // finally set background mode
1688 Qtx::BackgroundMode m = (Qtx::BackgroundMode)( stringToInt( bgMode, Qtx::ColorBackground,
1689 Qtx::NoBackground, Qtx::CustomGradientBackground ) );
1690 bgData.setMode( m );
1697 \class Qtx::Localizer
1698 \brief Localization helper
1700 This helper class can be used to solve the localization problems,
1701 usually related to the textual files reading/writing, namely when
1702 floating point values are read / written with API functions.
1703 The problem relates to such locale specific settings as decimal point
1704 separator, thousands separator, etc.
1706 To use the Localizer class, just create a local variable in the beginning
1707 of the code where you need to read / write data from textual file(s).
1708 The constructor of the class forces setting "C" locale temporariy.
1709 The destructor switches back to the initial locale.
1719 \brief Constructor. Forces "C" locale to be set.
1721 Qtx::Localizer::Localizer()
1723 myCurLocale = setlocale( LC_NUMERIC, 0 );
1724 setlocale( LC_NUMERIC, "C" );
1728 \brief Destructor. Reverts back to the initial locale.
1730 Qtx::Localizer::~Localizer()
1732 setlocale( LC_NUMERIC, myCurLocale.toLatin1().constData() );
1736 \class Qtx::BackgroundData
1737 \brief Stores background data
1739 This class is used to store background data. Depending on the mode,
1740 the background can be specified by:
1741 - image (by assigning the file name to be used as background texture), see setTexture(), setTextureShown()
1742 - single color (by assigning any color), see setColor()
1743 - simple two-color gradient (with the gradient type id and two colors), see setGradient( int, const QColor&, const QColor& )
1744 - complex gradient (by assigning arbitrary gradient data), see setGradient( const QGradient& )
1746 The class stores all the data passed to it, so switching between different modes can be done
1747 just by calling setMode() function.
1749 \note Texture is used with combination of the background mode.
1751 \note Two-color gradient is specified by two colors and integer identifier. The interpretation of
1752 this identifier should be done in the calling code.
1755 Qtx::BackgroundData bg;
1756 bg.setColor( QColor(100, 100, 100) ); // bg is switched to Qtx::ColorBackground mode
1757 bg.setGradient( Qt::Horizontal, Qt::gray, Qt::white ); // bg is switched to Qtx::ColorBackground mode
1758 QLinearGradient grad( 0,0,1,1 );
1759 grad.setColorAt( 0.0, Qt::gray );
1760 grad.setColorAt( 0.5, Qt::white );
1761 grad.setColorAt( 1.0, Qt::green );
1762 grad.setSpread( QGradient::PadSpread );
1763 bg.setGradient( grad ); // bg is switched to Qtx::CustomGradientBackground mode
1764 bg.setMode( Qtx::ColorBackground ); // bg is switched back to Qtx::ColorBackground mode
1765 bg.setTexture( "/data/images/background.png" ); // specify texture (in the centered mode by default)
1766 bg.setTextureShown( true ); // draw texture on the solid color background
1771 \brief Default constructor.
1772 Creates invalid background data.
1774 Qtx::BackgroundData::BackgroundData()
1775 : myTextureMode( Qtx::CenterTexture ), myGradientType( -1 ), myTextureShown( false )
1777 setMode( Qtx::NoBackground );
1782 Creates background data initialized with the specified color
1785 Qtx::BackgroundData::BackgroundData( const QColor& c )
1786 : myTextureMode( Qtx::CenterTexture ), myGradientType( -1 ), myTextureShown( false )
1793 Creates background data initialized with the specified two-color gradient
1794 \param type gradient type identifier
1795 \param c1 first gradient color
1796 \param c2 second gradient color
1797 \note the interpretation of the gradient identifier should be done in the calling code
1799 Qtx::BackgroundData::BackgroundData( int type, const QColor& c1, const QColor& c2 )
1800 : myTextureMode( Qtx::CenterTexture ), myGradientType( -1 ), myTextureShown( false )
1802 setGradient( type, c1, c2 );
1807 Creates background data initialized with the arbirtary gradient data
1808 \param grad gradient data
1810 Qtx::BackgroundData::BackgroundData( const QGradient& grad )
1811 : myTextureMode( Qtx::CenterTexture ), myGradientType( -1 ), myTextureShown( false )
1813 setGradient( grad );
1819 Qtx::BackgroundData::~BackgroundData()
1824 \brief Compares two background data objects
1826 bool Qtx::BackgroundData::operator==( const Qtx::BackgroundData& other ) const
1829 ( myMode == other.myMode ) &&
1830 ( myTextureMode == other.myTextureMode ) &&
1831 ( myFileName == other.myFileName ) &&
1832 ( myColors == other.myColors ) &&
1833 ( myGradientType == other.myGradientType ) &&
1834 ( myGradient == other.myGradient ) &&
1835 ( myTextureShown == other.myTextureShown );
1839 \brief Returns \c false if background data is not set (invalid)
1840 \return \c true if background data is valid or \c false otherwise
1843 bool Qtx::BackgroundData::isValid() const
1845 return myMode != Qtx::NoBackground;
1849 \brief Get background mode
1850 \return current background mode
1853 Qtx::BackgroundMode Qtx::BackgroundData::mode() const
1859 \brief Set background mode
1860 \param m background mode being set
1863 void Qtx::BackgroundData::setMode( const Qtx::BackgroundMode m )
1869 \brief Get file name used as a texture image
1870 \return path to the texture image file
1871 \sa setTexture(), setTextureShown()
1873 Qtx::TextureMode Qtx::BackgroundData::texture( QString& fileName ) const
1875 fileName = myFileName;
1876 return myTextureMode;
1880 \brief Set file name to be used as a texture image.
1882 \note To show texture image on the background it is necessary to call additionally
1883 setTextureShown() method.
1885 \param fileName path to the texture image file name
1886 \param m texture mode (Qtx::CenterTexture by default)
1887 \sa texture(), setTextureShown()
1889 void Qtx::BackgroundData::setTexture( const QString& fileName, const Qtx::TextureMode m )
1891 myFileName = fileName;
1896 \brief Check if "show texture" flag is switched on
1897 \return \c true if "show texture" flag is set or \c false otherwise
1898 \sa setTextureShown(), texture()
1900 bool Qtx::BackgroundData::isTextureShown() const
1902 return myTextureShown;
1906 \brief Specify if texture should be shown on the background or no.
1907 \param on \c true if texture should be shown or \c false otherwise
1908 \sa isTextureShown(), texture()
1910 void Qtx::BackgroundData::setTextureShown( bool on )
1912 myTextureShown = on;
1916 \brief Get background color. Returns null QColor if color is not set
1917 \return solid background color
1918 \sa setColor(), mode()
1920 QColor Qtx::BackgroundData::color() const
1922 return myColors.count() > 0 ? myColors[0] : QColor();
1926 \brief Set background color and switch to the Qtx::ColorBackground mode
1930 void Qtx::BackgroundData::setColor( const QColor& c )
1934 setMode( Qtx::ColorBackground );
1938 \brief Get simple gradient data.
1939 Returns -1 and null QColor for \a c1 and \a c2 if gradient data is not set
1940 \param c1 first gradient color is returned via this parameter
1941 \param c2 second gradient color is returned via this parameter
1942 \return current two-colored gradient mode type identifier
1943 \note the interpretation of the gradient identifier should be done in the calling code
1944 \sa setGradient(int, const QColor&, const QColor&), mode()
1946 int Qtx::BackgroundData::gradient( QColor& c1, QColor& c2 ) const
1948 c1 = myColors.count() > 0 ? myColors[0] : QColor();
1949 c2 = myColors.count() > 1 ? myColors[1] : ( myColors.count() > 0 ? myColors[0] : QColor() );
1950 return myGradientType;
1954 \brief Set simple background gradient data and switch to the Qtx::SimpleGradientBackground mode
1955 \param type two-colored gradient mode type identifier
1956 \param c1 first gradient color is returned via this parameter
1957 \param c2 second gradient color is returned via this parameter
1958 \note the interpretation of the gradient identifier should be done in the calling code
1959 \sa gradient(QColor&, QColor&), mode()
1961 void Qtx::BackgroundData::setGradient( int type, const QColor& c1, const QColor& c2 )
1964 myColors << c1 << c2;
1965 myGradientType = type;
1966 setMode( Qtx::SimpleGradientBackground );
1970 \brief Get complex gradient data.
1971 Returns QGradient of QGradient::NoGradient if gradient data is not set
1972 \note This function does not transform simple gradient data set with
1973 setGradient( const QString&, const QColor&, const QColor& ) to QGradient class
1974 \return gradient data
1975 \sa setGradient(const QGradient&), mode()
1977 const QGradient* Qtx::BackgroundData::gradient() const
1983 \brief Set complex background gradient data and switch to the Qtx::CustomGradientBackground mode
1984 \param grad gradient data (QLinearGradient, QRadialGradient or QConicalGradient)
1985 \sa gradient(), mode()
1987 void Qtx::BackgroundData::setGradient( const QGradient& grad )
1990 setMode( Qtx::CustomGradientBackground );
1994 \brief Convert string representation of version identifier to the numerical value.
1995 Resulting value can be used for comparison of different versions (lower, higher, equal).
1997 String representation of the version consists of zero or more components:
1999 [major[.minor[.release[patchid]]]]
2002 - major is version major number
2003 - minor is version minor number
2004 - release is version release number
2005 - patchid is a version dev identifier which is one of the following
2006 * 1 letter optionally followed by 1 or 2 digits, e.g. "a" for "alpha", "b1" for "beta 1"
2007 * "rc" optionally followed by 1 or 2 digits, e.g. "rc1" for "release candidate 1"
2008 * "dev" for development version (note: 7.4.0dev > 7.4.0, 7.4.0dev < 7.4.1, 7.4.0dev < 7.4.0a1)
2010 If version string does not include any component or has invalid format, the function returns 0.
2014 1.2.3a - version 1.2.3 alpha
2015 3.3.3b1 - version 3.3.3 beta 1
2016 7.4.0rc1 - version 7.4.0 release candidate 1
2017 7.4.0dev - dev version, i.e. future version 7.4.1 (or 7.5.0)
2019 \param version string representation of version
2020 \return numerical identifier of the version
2022 long Qtx::versionToId( const QString& version )
2026 QRegExp vers_exp( "^([0-9]+)([A-Z]|RC|DEV)?([0-9]{0,2})$", Qt::CaseInsensitive );
2028 QStringList vers = version.split( ".", QString::SkipEmptyParts );
2029 int major=0, minor=0;
2030 int release = 0, dev1 = 0, dev2 = 0;
2031 if ( vers.count() > 0 ) major = vers[0].toInt();
2032 if ( vers.count() > 1 ) minor = vers[1].toInt();
2033 if ( vers.count() > 2 ) {
2034 if ( vers_exp.indexIn( vers[2] ) != -1 ) {
2035 release = vers_exp.cap( 1 ).toInt();
2036 QString tag = vers_exp.cap( 2 ).toLower();
2037 if ( !tag.isEmpty() ) {
2038 // patchid is subtracted from version number
2039 // a = 55 --> -(55 * 100) + patch number --> 4500..4599, e.g. 7.4.1a1 -> 704004501
2040 // b = 54 --> -(54 * 100) + patch number --> 4600..4699, e.g. 7.4.1b1 -> 704004601
2041 // c = 53 --> -(53 * 100) + patch number --> 4700..4799, e.g. 7.4.1c1 -> 704004701
2043 // z = 30 --> -( 1 * 100) + patch number --> 7000..7099, e.g. 7.4.1z1 -> 704007001
2044 // rc = 1 --> -( 1 * 100) + patch number --> 9900..9999, e.g. 7.4.1rc1 -> 704009901
2045 // dev = -1 --> +( 1 * 100) + patch number --> 0100..0199, e.g. 7.4.1dev -> 704010100
2047 // i.e. "a" < "b" < ... < "z" < "rc" < [stable] < "dev"
2050 else if ( tag == "dev" )
2053 dev1 = (int)( QChar('z').toLatin1() ) - (int)( tag[ 0 ].toLatin1() ) + 30;
2055 if ( !vers_exp.cap( 3 ).isEmpty() )
2056 dev2 = vers_exp.cap( 3 ).toInt();
2060 int dev = dev1*100-dev2;
2063 id*=100; id+=release;
2071 \brief Get Qt installation directory
2073 The function tries to detect qt installation directory by analyzing the system variables in the following order:
2079 Optional parameter \a context allows obtaining subdirectory in the Qt installation directory.
2081 \param context optional sub-directory
2082 \return path to the Qt installation directory (or its sub-folder, if \a context is specified)
2085 QString Qtx::qtDir( const QString& context )
2087 const char* vars[] = { "QT5_ROOT_DIR", "QT4_ROOT_DIR", "QT_ROOT_DIR", "QTDIR" };
2089 for (uint i = 0; i < sizeof(vars)/sizeof(vars[0]) && qtPath.isEmpty(); i++ )
2090 qtPath = qgetenv( vars[i] );
2091 if ( !qtPath.isEmpty() && !context.isEmpty() )
2092 qtPath = QDir( qtPath ).absoluteFilePath( context );
2097 Creates font from string description
2099 QFont Qtx::stringToFont( const QString& fontDescription )
2102 if ( fontDescription.trimmed().isEmpty() || !font.fromString( fontDescription ) )
2103 font = QFont( "Courier", 11 );
2109 #include <X11/Xlib.h>
2113 \brief Open the default X display and returns pointer to it.
2114 This method is available on Linux only.
2115 \return Pointer to X display.
2118 void* Qtx::getDisplay()
2120 static Display* pDisplay = NULL;
2122 pDisplay = XOpenDisplay( NULL );
2127 \brief Returns pointer to X visual suitable for 3D rendering.
2128 This method is available on Linux only.
2129 \return Pointer to X visual.
2132 Qt::HANDLE Qtx::getVisual()
2134 Qt::HANDLE res = (Qt::HANDLE)NULL;
2136 Display* pDisplay = (Display*)getDisplay();
2143 // Make sure OpenGL's GLX extension supported
2144 if( !glXQueryExtension( pDisplay, &errorBase, &eventBase ) ){
2145 qCritical( "Could not find glx extension" );
2149 // Find an appropriate visual
2151 int doubleBufferVisual[] = {
2152 GLX_RGBA, // Needs to support OpenGL
2153 GLX_DEPTH_SIZE, 16, // Needs to support a 16 bit depth buffer
2154 GLX_DOUBLEBUFFER, // Needs to support double-buffering
2155 GLX_STEREO, // Needs to support stereo rendering
2156 GLX_STENCIL_SIZE, 1,
2160 // Try for the double-bufferd visual first
2161 XVisualInfo *visualInfo = NULL;
2162 visualInfo = glXChooseVisual( pDisplay, DefaultScreen(pDisplay), doubleBufferVisual );
2164 if( visualInfo == NULL ){
2165 qCritical( "Could not find matching glx visual" );
2169 qDebug() << "Picked visual 0x" << hex << XVisualIDFromVisual( visualInfo->visual );
2170 res = (Qt::HANDLE)( visualInfo->visual );
2178 \class Qtx::CmdLineArgs
2179 \brief Get access to the command line arguments in the C-like manner.
2181 This class translates command line arguments stored in QApplication in form of QStrlingList
2182 to the char* array, in the same way as they specified to main() function.
2184 Constructor of class allocates required memory to store arguments; destructor deallocates it,
2185 This allows using this class as a local variable:
2188 Qtx::CmdLineArgs args;
2189 some_function(args.argc(), args.argv()); // function that has main()-like syntax.
2194 \brief Default constructor.
2196 Qtx::CmdLineArgs::CmdLineArgs()
2198 QStringList args = QCoreApplication::arguments();
2199 myArgc = args.size();
2200 myArgv = new char*[myArgc];
2201 for ( int i = 0; i < myArgc; i++ ) {
2202 QByteArray ba = args[i].toUtf8();
2203 myArgv[i] = qstrdup(ba.constData());
2208 \brief Destructor. Deallocates the array with command line arguments
2210 Qtx::CmdLineArgs::~CmdLineArgs()
2212 for ( int i = 0; i < myArgc; i++ )
2218 \brief Get number of command line arguments
2219 \return number of arguments
2221 int Qtx::CmdLineArgs::argc() const
2227 \brief Get command line arguments
2228 \return command line arguments
2230 char** Qtx::CmdLineArgs::argv() const