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>
41 #if QT_VERSION > QT_VERSION_CHECK(5, 0, 0)
42 #include <QSurfaceFormat>
50 #define BICOLOR_CHANGE_HUE
53 \brief Auxiliary function converting string \a str to the integer value.
54 Parameter \a defVal specifies default value that is returned if conversion can't be done.
55 Parameters \a minVal and \a maxVal limit the resulting value.
56 \param str string being converted
57 \param defVal default value
58 \param minVal minimum allowed value
59 \param maxVal maximum allowed value
60 \return integer value obtained from the string
63 static int stringToInt( const QString& str, int defVal, int minVal, int maxVal )
66 int v = str.toInt( &ok );
67 if ( !ok ) v = defVal;
68 return qMin( qMax( v, minVal ), maxVal );
73 \brief A set of helpful utility functions.
75 The class implements a set of the static functions which can be used
76 for the different purposes:
77 - specify tab order for the set of widgets: setTabOrder()
78 - align one widget to the coordinates of the another one: alignWidget()
79 - remove extra separators from the menu or toolbar: simplifySeparators()
80 - retrieve directory, file name and extension parts of the path:
81 dir(), file(), extension()
82 - get the path to the temporary directory: tmpDir()
83 - create or remove a directory (recursively): mkDir(), rmDir()
84 - convert text file from DOS to UNIX native format: dos2unix()
85 - convert a picture to the gray scale: grayscale()
90 \brief Convert character array (ASCII string) to the QString.
91 \param str character array
92 \param len array length, if < 0, the array should be zero-terminated
93 \return QString object
95 QString Qtx::toQString( const char* str, const int len )
97 return toQString( (unsigned char*)str, len );
101 \brief Convert integer array (UNICODE string) to the QString.
102 \param str integer array
103 \param len array length, if < 0, the array should be zero-terminated
104 \return QString object
106 QString Qtx::toQString( const short* str, const int len )
108 return toQString( (unsigned short*)str, len );
112 \brief Convert character array (ASCII string) to the QString.
113 \param str character array
114 \param len array length, if < 0, the array should be zero-terminated
115 \return QString object
117 QString Qtx::toQString( const unsigned char* str, const int len )
120 const unsigned char* s = str;
121 while ( len < 0 || res.length() < len )
126 res.append( QChar( *s ) );
133 \brief Convert integer array (UNICODE string) to the QString.
134 \param str integer array
135 \param len array length, if < 0, the array should be zero-terminated
136 \return QString object
138 QString Qtx::toQString( const unsigned short* str, const int len )
141 const unsigned short* s = str;
142 while ( len < 0 || res.length() < len )
147 res.append( QChar( *s ) );
154 \brief Set tab order for specified list of widgets.
156 The function has arbitrary number of parameters, each should be
157 hovewer of QWidget* type. Last parameter should be null pointer.
159 \param first first widget in the sequence
161 void Qtx::setTabOrder( QWidget* first, ... )
164 va_start( wids, first );
168 QWidget* cur = first;
171 widList.append( cur );
172 cur = va_arg( wids, QWidget* );
175 setTabOrder( widList );
179 \brief Set tab order for specified list of widgets.
180 \param widgets list of widgets
182 void Qtx::setTabOrder( const QWidgetList& widgets )
184 if ( widgets.count() < 2 )
188 for ( QWidgetList::const_iterator it = widgets.begin(); it!= widgets.end(); ++it )
192 QWidget::setTabOrder( prev, next );
198 \brief Align widget \a src relative to widget \a ref acording to the
199 alignment flags \a alignFlags.
200 \param src source widget (being aligned)
201 \param ref reference widget (source widget being aligned to)
202 \param alignFlags alignment flags (Qtx::AlignmentFlags)
204 void Qtx::alignWidget( QWidget* src, const QWidget* ref, const int alignFlags )
206 if ( !src || !ref || !alignFlags )
209 QPoint srcOri = src->pos();
210 QPoint refOri = ref->pos();
211 if ( src->parentWidget() && !src->isTopLevel() )
212 srcOri = src->parentWidget()->mapToGlobal( srcOri );
213 if ( ref->parentWidget() && !ref->isTopLevel() )
214 refOri = ref->parentWidget()->mapToGlobal( refOri );
216 int x = srcOri.x(), y = srcOri.y();
217 int refWidth = ref->frameGeometry().width(), refHei = ref->frameGeometry().height();
218 int srcWidth = src->frameGeometry().width(), srcHei = src->frameGeometry().height();
221 srcWidth = src->sizeHint().width();
223 srcHei = src->sizeHint().height();
226 if ( ref->isTopLevel() && ref->isMaximized() &&
227 src->isTopLevel() && !src->isMaximized() )
228 border = ( src->frameGeometry().width() - src->width() ) / 2;
230 if ( alignFlags & Qtx::AlignLeft )
231 x = refOri.x() + border;
232 if ( alignFlags & Qtx::AlignOutLeft )
233 x = refOri.x() - srcWidth - border;
234 if ( alignFlags & Qtx::AlignRight )
235 x = refOri.x() + refWidth - srcWidth - border;
236 if ( alignFlags & Qtx::AlignOutRight )
237 x = refOri.x() + refWidth + border;
238 if ( alignFlags & Qtx::AlignTop )
239 y = refOri.y() + border;
240 if ( alignFlags & Qtx::AlignOutTop )
241 y = refOri.y() - srcHei - border;
242 if ( alignFlags & Qtx::AlignBottom )
243 y = refOri.y() + refHei - srcHei - border;
244 if ( alignFlags & Qtx::AlignOutBottom )
245 y = refOri.y() + refHei + border;
246 if ( alignFlags & Qtx::AlignHCenter )
247 x = refOri.x() + ( refWidth - srcWidth ) / 2;
248 if ( alignFlags & Qtx::AlignVCenter )
249 y = refOri.y() + ( refHei - srcHei ) / 2;
251 if ( src->parentWidget() && !src->isTopLevel() )
253 QPoint pos = src->parentWidget()->mapFromGlobal( QPoint( x, y ) );
258 QWidget* desk = QApplication::desktop();
259 if ( desk && x + srcWidth + border > desk->width() )
260 x = desk->width() - srcWidth - border;
261 if ( desk && y + srcHei + border > desk->height() )
262 y = desk->height() - srcHei - border;
271 \brief Remove (recursively) unnecessary separators from the menu or toolbar.
272 \param wid widget, should be of QMenu* or QToolBar* class
274 void Qtx::simplifySeparators( QWidget* wid, const bool recursive )
279 QList<QAction*> items = wid->actions();
280 if ( items.isEmpty() )
284 for ( int i = 0; i < items.count(); i++ )
286 QAction* a = items[i];
287 if ( a->isSeparator() ) {
288 a->setVisible(action);
291 else if ( a->isVisible() ) {
293 if ( recursive && a->menu() )
294 simplifySeparators( a->menu(), recursive );
299 for ( int i = items.count() - 1; i > 0; i-- ) {
300 QAction* a = items[i];
301 if ( a->isSeparator() ) {
302 a->setVisible(action);
305 else if ( a->isVisible() )
311 \brief Return \c true if specified \a parent is a parent object
312 of given \a child (in terms of QObject).
314 This function works recursively. It means that \a true is also
315 returned if \a parent is a grand-father, grand-grand-father, etc
316 of \a child. If the same object is given as both \a parent and
317 \a child, \c true is also returned.
319 \param child child object
320 \param parent parent object
321 \return \c true if the \a parent is a parent of \a child
323 bool Qtx::isParent( QObject* child, QObject* parent )
325 if ( !child || !parent )
329 QObject* obj = child;
330 while ( !res && obj )
339 \brief Find the parent object of class specified by \a className (in terms of QObject).
341 \param obj current object
342 \param className class name of the parent
343 \return parent object or null pointer if the parent not found
345 QObject* Qtx::findParent( QObject* obj, const char* className )
350 if ( !className || !strlen( className ) )
351 return obj->parent();
354 QObject* p = obj->parent();
357 if ( p->inherits( className ) )
366 \brief Return directory part of the file path.
368 If the file path does not include directory part (the file is in the
369 current directory), null string is returned.
371 \param path file path
372 \param abs if true (default) \a path parameter is treated as absolute file path
373 \return directory part of the file path
375 QString Qtx::dir( const QString& path, const bool abs )
377 QDir aDir = QFileInfo( path ).dir();
378 QString dirPath = abs ? aDir.absolutePath() : aDir.path();
379 if ( dirPath == QString( "." ) )
385 \brief Return file name part of the file path.
387 \param path file path
388 \param withExt if true (default) complete file name (with all
389 extension except the last) is returned, otherwise only base name
391 \return file name part of the file path
393 QString Qtx::file( const QString& path, bool withExt )
395 QString fPath = path;
396 while ( !fPath.isEmpty() && ( fPath[fPath.length() - 1] == '\\' || fPath[fPath.length() - 1] == '/' ) )
397 fPath.remove( fPath.length() - 1, 1 );
400 return QFileInfo( fPath ).fileName();
402 return QFileInfo( fPath ).completeBaseName();
406 \brief Return extension part of the file path.
408 \param path file path
409 \param full if true complete extension (all extensions, dot separated)
410 is returned, otherwise (default) only last extension is returned
411 \return extension part of the file path
413 QString Qtx::extension( const QString& path, const bool full )
415 return full ? QFileInfo( path ).completeSuffix() : QFileInfo( path ).suffix();
419 \brief Convert the given parameter to the platform-specific library name.
421 The function appends platform-specific prefix (lib) and suffix (.dll/.so)
422 to the library file name.
423 For example, if \a str = "mylib", "libmylib.so" is returned for Linux and
424 mylib.dll for Windows.
426 \param str short library name
427 \return full library name
429 QString Qtx::library( const QString& str )
431 QString path = dir( str, false );
432 QString name = file( str, false );
433 QString ext = extension( str );
436 if ( !name.startsWith( "lib" ) )
437 name = QString( "lib" ) + name;
441 QString libExt( "dll" );
442 #elif defined(__APPLE__)
443 QString libExt( "dylib" );
445 QString libExt( "so" );
448 if ( ext.toLower() != QString( "so" ) && ext.toLower() != QString( "dll" ) && ext.toLower() != QString( "dylib" ) )
450 if ( !name.isEmpty() && !ext.isEmpty() )
451 name += QString( "." );
457 QString fileName = addSlash( path ) + name + QString( "." ) + ext;
463 \brief Get the temporary directory name.
464 \return temporary directory (platform specific)
466 QString Qtx::tmpDir()
468 const char* tmpdir = ::getenv( "TEMP" );
470 tmpdir = ::getenv ( "TMP" );
479 return QString( tmpdir );
483 \brief Create directory recursively including all intermediate sub directories.
484 \return \c true if the directory is successfully created and \c false otherwise
486 bool Qtx::mkDir( const QString& dirPath )
488 return QDir().mkpath( dirPath );
492 \brief Remove directory recursively including all subdirectories and files.
493 \return \c true if the directory is successfully removed and \c false otherwise
495 bool Qtx::rmDir( const QString& thePath )
497 QFileInfo fi( thePath );
503 stat = QFile::remove( thePath );
504 else if ( fi.isDir() )
506 QDir aDir( thePath );
507 QFileInfoList anEntries = aDir.entryInfoList();
508 for ( QFileInfoList::iterator it = anEntries.begin(); it != anEntries.end(); ++it )
511 if ( inf.fileName() == "." || inf.fileName() == ".." )
513 stat = stat && rmDir( inf.absoluteFilePath() );
515 stat = stat && aDir.rmdir( thePath );
521 \brief Add a slash (platform-specific) to the end of \a path
522 if it is not already there.
523 \param path directory path
524 \return modified path (with slash added to the end)
526 QString Qtx::addSlash( const QString& path )
529 if ( !res.isEmpty() && res.at( res.length() - 1 ) != QChar( '/' ) &&
530 res.at( res.length() - 1 ) != QChar( '\\' ) )
531 res += QDir::separator();
536 \brief Convert text file from DOS format to UNIX.
538 The function replaces "LF/CR" symbols sequence by "LF" symbol.
540 \param absName file name
541 \return \c true if the file is converted successfully and \c false in
544 bool Qtx::dos2unix( const QString& absName )
546 FILE* src = ::fopen( absName.toLatin1(), "rb" );
550 /* we'll use temporary file */
551 char temp[512] = { '\0' };
552 QString dir = Qtx::dir( absName );
553 FILE* tgt = ::fopen( strcpy( temp, ::tempnam( dir.toLatin1(), "__x" ) ), "wb" );
557 /* temp -> result of conversion */
558 const char CR = 0x0d;
559 const char LF = 0x0a;
560 bool waitingLF = false;
565 char inbuf[512], outbuf[512];
568 int nbread = ::fread( inbuf, 1, sizeof( inbuf ), src );
569 for ( int incnt = 0; incnt < nbread; incnt++ )
574 if ( inbuf[incnt] == LF )
575 outbuf[outcnt++] = LF;
577 outbuf[outcnt++] = CR;
579 else if ( inbuf[incnt] == CR )
582 outbuf[outcnt++] = inbuf[incnt];
585 /* check last sym in buffer */
586 waitingLF = ( inbuf[nbread - 1] == CR );
588 /* write converted buffer to temp file */
589 int nbwri = ::fwrite( outbuf, 1, outcnt, tgt );
590 if ( nbwri != outcnt )
594 QFile::remove( QString( temp ) );
597 if ( nbread != sizeof( inbuf ) )
598 break; /* converted ok */
603 /* rename temp -> src */
604 if ( !QFile::remove( absName ) )
607 return QDir().rename( QString( temp ), absName );
611 \brief Create path completer which can be used in the widgets
612 to provide auto completions.
614 Create an instance of QCompleter class and returns the pointer on it.
615 The calling function is responsible to the desstroying of the created
618 The QCompleter class provides completions based on a item model and can be
619 used in such as QLineEdit and QComboBox.
620 When the user starts typing a word, QCompleter suggests possible ways of
621 completing the word, based on a word list.
623 \param type path type (Qtx::PathType)
624 \param filter file/directory filters (list of wildcards, separated by ";;")
625 \return a pointer to the created completer
627 QCompleter* Qtx::pathCompleter( const PathType type, const QString& filter )
630 QStringList filterList = filter.split( ";;" );
631 for ( QStringList::const_iterator it = filterList.begin(); it != filterList.end(); ++it )
633 QRegExp rx( "[\\s\\w,;]*\\(?\\*\\.([\\w]+)\\)?[\\d\\s\\w]*" );
635 while ( ( index = rx.indexIn( *it, index ) ) != -1 )
637 extList.append( QString( "*.%1" ).arg( rx.cap( 1 ) ) );
638 index += rx.matchedLength();
642 QDir::Filters filters = 0;
647 filters = QDir::AllEntries | QDir::AllDirs | QDir::NoDotAndDotDot;
650 filters = QDir::Drives | QDir::Dirs | QDir::NoDotAndDotDot;
654 QDirModel* dm = new QDirModel( extList, filters, QDir::Unsorted );
655 QCompleter* cmp = new QCompleter( dm, 0 );
656 dm->setParent( cmp );
662 \brief Parse given string to retrieve environment variable.
664 Looks through the string for the environment variable patterns.
665 If string contains variable satisfying any pattern, the variable name
666 is returned, start index of the variable is returned in the \a start parameter,
667 and length of the variable is returned in the \a len parameter.
669 Supported environment variables definitions:
670 - ${name} or $name : Linux shell variable
671 - $(name) : GNU make substitution
672 - %name% : Windows shell variable
673 - %(name)s : Python substitutions:
675 \param str string being processed
676 \param start if variable is found, this parameter contains its starting
677 position in the \a str
678 \param len if variable is found, this parameter contains its length
679 \return first found variable or null QString if there is no ones
681 QString Qtx::findEnvVar( const QString& str, int& start, int& len )
687 rxList << "\\$\\{([a-zA-Z][a-zA-Z_0-9]*)\\}"; // ${name}
688 rxList << "\\$([a-zA-Z][a-zA-Z_0-9]*)"; // $name
689 rxList << "\\$\\(([a-zA-Z][a-zA-Z_0-9]*)\\)"; // $(name)
690 rxList << "%([a-zA-Z][a-zA-Z0-9_]*)%"; // %name%
691 rxList << "%\\(([a-zA-Z][a-zA-Z_0-9]*)\\)s"; // %(name)s
693 for ( int i = 0; i < rxList.count() && varName.isEmpty(); ++i )
695 QRegExp rx(rxList[i]);
696 int pos = rx.indexIn( str, start );
699 varName = rx.cap( 1 );
701 len = rx.matchedLength();
708 \brief Substitute environment variables by their values.
710 Environment variable is substituted by its value.
712 \param str string to be processed
713 \return processed string (with all substitutions made)
715 QString Qtx::makeEnvVarSubst( const QString& str, const SubstMode mode )
720 QMap<QString, int> ignoreMap;
722 int start( 0 ), len( 0 );
725 QString envName = findEnvVar( res, start, len );
726 if ( envName.isNull() )
730 if ( ::getenv( envName.toLatin1() ) || mode == Always )
731 newStr = QString( ::getenv( envName.toLatin1() ) );
733 if ( newStr.isNull() )
735 if ( ignoreMap.contains( envName ) )
740 ignoreMap.insert( envName, 0 );
742 res.replace( start, len, newStr );
745 res.replace( "$$", "$" );
746 res.replace( "%%", "%" );
753 \brief Pack the specified color into integer RGB set.
754 \param c unpacked color
757 int Qtx::rgbSet( const QColor& c )
759 return rgbSet( c.red(), c.green(), c.blue() );
763 \brief Pack the specified RGB color components into integer RGB set.
764 \param r red component
765 \param g green component
766 \param b blue component
769 int Qtx::rgbSet( const int r, const int g, const int b )
771 return ( ( ( 0xff & r ) << 16 ) + ( ( 0xff & g ) << 8 ) + ( 0xff & b ) );
775 \brief Unpack the specified integer RGB set to the color.
776 \param rgb packed color
777 \return unpacked color (QColor)
779 QColor Qtx::rgbSet( const int rgb )
782 rgbSet( rgb, r, g, b );
783 return QColor( r, g, b );
787 \brief Unpack the specified integer RGB set to the three RGB components.
788 \param rgb packed color
789 \param r returned unpacked red component
790 \param g returned unpacked green component
791 \param b returned unpacked blue component
793 void Qtx::rgbSet( const int rgb, int& r, int& g, int& b )
795 r = ( rgb >> 16 ) & 0xff;
796 g = ( rgb >> 8 ) & 0xff;
801 \brief Return the color specified by the index between min (blue) and max (red).
802 \param index color index
803 \param min required minimum hue value
804 \param max required maximum hue value
805 \return resulting color
807 QColor Qtx::scaleColor( const int index, const int min, const int max )
809 static const int HUE[10] = {230, 210, 195, 180, 160, 80, 60, 50, 30, 0};
815 double aPosition = 9.0 * ( index - min ) / ( max - min );
816 if ( aPosition > 0.0 )
818 if ( aPosition >= 9.0 )
822 int idx = (int)aPosition;
823 hue = HUE[idx] + int( ( aPosition - idx ) * ( HUE[idx + 1] - HUE[idx] ) );
828 return QColor::fromHsv( hue, 255, 255 );
832 \brief Generate required number of colors aligned from blue to red.
833 \param num required number of colors
834 \param lst returned set of colors
836 void Qtx::scaleColors( const int num, QColorList& lst )
839 for ( int i = 0; i < num; i++ )
840 lst.append( scaleColor( i, 0, num - 1 ) );
844 \brief Scale the pixmap to the required size.
846 If \a h is 0 (default) the value of \a w is used instead (to create
849 \param icon pixmap to be resized
850 \param w required pixmap width
851 \param h required pixmap height
852 \return scaled pixmap
854 QPixmap Qtx::scaleIcon( const QPixmap& icon, const unsigned w, const unsigned h )
857 int aw = w, ah = h <= 0 ? w : h;
858 if ( icon.isNull() || aw <= 0 || ah <= 0 || ( aw == icon.width() && ah == icon.height() ) )
861 p = icon.fromImage( icon.toImage().scaled( aw, ah, Qt::KeepAspectRatio, Qt::SmoothTransformation ) );
866 \brief Convert given image to the grayscale format.
867 \param img initial image
868 \return converted to the grayscale image
870 QImage Qtx::grayscale( const QImage& img )
874 int colNum = res.colorCount();
877 for ( int i = 0; i < colNum; i++ )
878 res.setColor( i, qGray( res.color( i ) ) );
882 for ( int y = 0; y < res.height(); y++ )
884 for ( int x = 0; x < res.width(); x++ )
886 QRgb pix = res.pixel( x, y );
887 res.setPixel( x, y, qRgba( qGray( pix ), qGray( pix ), qGray( pix ), qAlpha( pix ) ) );
896 \brief Convert given pixmap to the grayscale format.
897 \param pix initial pixmap
898 \return converted to the grayscale pixmap
900 QPixmap Qtx::grayscale( const QPixmap& pix )
903 res.fromImage( grayscale( pix.toImage() ) );
908 \brief Create transparent image.
909 \param w required image width
910 \param h required image height
911 \param d required image depth
912 \return generated image
914 QImage Qtx::transparentImage( const int w, const int h, const int d )
920 fmt = QImage::Format_Mono;
923 fmt = QImage::Format_Indexed8;
929 fmt = QImage::Format_ARGB32;
933 QImage img( w, h, fmt );
936 // img.setAlphaBuffer( true );
937 for ( int i = 0; i < img.height(); i++ )
938 for ( int j = 0; j < img.width(); j++ )
939 img.setPixel( j, i, qRgba( 0, 0, 0, 0 ) );
945 \brief Create transparent pixmap.
946 \param w required image width
947 \param h required pixmap height
948 \param d required pixmap depth
949 \return generated pixmap
951 QPixmap Qtx::transparentPixmap( const int w, const int h, const int d )
954 QImage img = transparentImage( w, h, d );
956 pix.fromImage( img );
961 \brief Create composite pixmap.
963 Pixmap \a pix is drawn over pixmap \a dest with coordinates
964 specified relatively to the upper left corner of \a dest.
965 If \a dest is not given, the new empty pixmap with appropriate size created instead.
967 \param pix source pixmap
968 \param x horizontal shift
969 \param y vertical shift
970 \param dest background pixmap
971 \return resulting pixmap
973 QPixmap Qtx::composite( const QPixmap& pix, const int x, const int y, const QPixmap& dest )
978 int width = qMax( pix.width() + x, dest.width() );
979 int height = qMax( pix.height() + y, dest.height() );
981 QPixmap res( width, height );
982 QImage img = transparentImage( width, height, 32 );
986 p.fillRect( 0, 0, width, height, QBrush( Qt::white ) );
988 if ( !dest.isNull() )
990 p.drawPixmap( 0, 0, dest );
991 QImage temp = dest.toImage();
992 for ( int i = 0; i < temp.width() && i < img.width(); i++ )
994 for ( int j = 0; j < temp.height() && j < img.height(); j++ )
996 if ( temp.hasAlphaChannel() )
997 img.setPixel( i, j, temp.pixel( i, j ) );
1000 QRgb p = temp.pixel( i, j );
1001 img.setPixel( i, j, qRgba( qRed( p ), qGreen( p ), qBlue( p ), 255 ) );
1007 p.drawPixmap( x, y, pix );
1008 QImage temp = pix.toImage();
1009 for ( int c = x; c < temp.width() + x && c < img.width(); c++ )
1011 for ( int r = y; r < temp.height() + y && r < img.height(); r++ )
1013 if ( qAlpha( temp.pixel( c - x, r - y ) ) > 0 )
1014 img.setPixel( c, r, temp.pixel( c - x, r - y ) );
1020 for ( int ai = 0; ai < img.width(); ai++ )
1022 for ( int aj = 0; aj < img.height(); aj++ )
1024 if ( qAlpha( img.pixel( ai, aj ) ) < 1 )
1025 img.setPixel( ai, aj, qRgba( 255, 255, 255, 255 ) );
1027 img.setPixel( ai, aj, qRgba( 0, 0, 0, 0 ) );
1031 QBitmap bmp( width, height );
1032 bmp.fromImage( img, Qt::ColorMode_Mask | Qt::ThresholdDither );
1039 \brief Convert color to the string representation.
1041 The resulting string is in the one of two possible formats
1042 (\c RR, \c GG, \c BB and \c AA value represent red, green, blue
1043 and alpha components of the color):
1044 - if color has alpha channel : "#RR,#GG,#BB,#AA"
1045 - if color does not have alpha channel : "#RRGGBB"
1047 If color is invalid, null string is returned.
1049 Backward conversion can be done with stringToColor() method.
1051 \param color color to be converted
1052 \return string representation of the color
1056 QString Qtx::colorToString( const QColor& color )
1059 if ( color.isValid() )
1061 if ( color.alpha() != 255 )
1064 vals << QString( "#%1" ).arg( color.red(), 0, 16 );
1065 vals << QString( "#%1" ).arg( color.green(), 0, 16 );
1066 vals << QString( "#%1" ).arg( color.blue(), 0, 16 );
1067 vals << QString( "#%1" ).arg( color.alpha(), 0, 16 );
1068 str = vals.join( "," );
1079 \brief Create color from the string representation.
1081 The parameter \a str must be in the one of following formats
1082 (\c RR, \c GG, \c BB and \c AA value represent red, green, blue
1083 and alpha components of the color):
1084 - "#RR,#GG,#BB[,#AA]" or "#RR #GG #BB[ #AA]" (\c RR, \c GG, \c BB
1085 and optional \c AA values represent red, green, blue and alpha
1086 components of the color in hexadecimal form)
1087 - "RR,GG,BB[,AA]" or "RR GG BB[ AA]" (\c RR, \c GG, \c BB
1088 and optional \c AA values represent red, green, blue and alpha
1089 components of the color in decimal form)
1090 - "#RRGGBB" - (\c RR, \c GG and \c BB values represent red, green and blue
1091 components of the color in hexadecimal form)
1092 - an integer value representing packed color components (see rgbSet())
1093 - a name from the list of colors defined in the list of SVG color keyword names
1094 provided by the World Wide Web Consortium; for example, "steelblue" or "gainsboro".
1096 Backward conversion can be done with colorToString() method.
1098 \param str string representation of the color
1099 \param color resulting color value
1100 \return \c true if the conversion is successful and \c false otherwise
1102 \sa colorToString(), rgbSet()
1104 bool Qtx::stringToColor( const QString& str, QColor& color )
1107 QStringList vals = str.split( QRegExp( "[\\s|,]" ), QString::SkipEmptyParts );
1110 for ( QStringList::const_iterator it = vals.begin(); it != vals.end() && res; ++it )
1113 if ( (*it).startsWith( "#" ) )
1114 num = (*it).mid( 1 ).toInt( &res, 16 );
1116 num = (*it).toInt( &res, 10 );
1121 res = res && nums.count() >= 3;
1123 color.setRgb( nums[0], nums[1], nums[2] );
1127 int pack = str.toInt( &res );
1129 color = Qtx::rgbSet( pack );
1134 color = QColor( str );
1135 res = color.isValid();
1142 \brief Convert bi-color value to the string representation.
1144 Bi-color value is specified as main color and integer delta
1145 value that is used to calculate secondary color by changing
1146 paremeters of the main color ("saturation" and "value"
1147 components in HSV notation).
1149 The resulting string consists of two sub-strings separated by
1150 '|' symbol. The first part represents main color
1151 (see colorToString() for more details), the second part is a
1154 Backward conversion can be done with stringToBiColor() method.
1156 \param color color to be converted
1157 \param delta delta value
1158 \return string representation of the bi-color value
1160 \sa stringToBiColor(), stringToColor()
1162 QString Qtx::biColorToString( const QColor& color, const int delta )
1164 return QString("%1|%2").arg( Qtx::colorToString( color ) ).arg( delta );
1168 \brief Restore bi-color value from the string representation.
1170 Bi-color value is specified as main color and integer delta
1171 value that is used to calculate secondary color by changing
1172 paremeters of the main color ("saturation" and "value"
1173 components in HSV notation).
1175 The parameter \a str should consist of two sub-strings separated
1176 by '|' symbol. The first part represents main color
1177 (see stringToColor() for more details), the second part is a
1180 Backward conversion can be done with biColorToString() method.
1182 \param str string representation of the bi-color value
1183 \param color resulting color value
1184 \param delta resulting delta value
1185 \return \c true if the conversion is successful and \c false otherwise
1187 \sa biColorToString(), stringToColor(), rgbSet()
1189 bool Qtx::stringToBiColor( const QString& str, QColor& color, int& delta )
1191 QStringList data = str.split( "|", QString::KeepEmptyParts );
1194 bool ok = data.count() > 0 && Qtx::stringToColor( data[0], c );
1196 if ( data.count() > 1 ) d = data[1].toInt( &dok );
1198 color = ok ? c : QColor();
1204 \brief Compute secondary color value from specified main color
1207 Secondary color is calculated by changing paremeters of the main
1208 color ("saturation" and "value" components in HSV notation) using
1211 If main color is invalid, result of the function is also invalid color.
1213 \param color source main color
1214 \param delta delta value
1215 \return resulting secondary color
1217 \sa biColorToString(), stringToBiColor()
1219 QColor Qtx::mainColorToSecondary( const QColor& color, int delta )
1222 if ( cs.isValid() ) {
1223 int val = qMin( 255, qMax( cs.value() + delta, 0 ) );
1224 int sat = qMin( 255, qMax( cs.saturation() + delta-(val-cs.value()), 0 ) );
1225 #ifdef BICOLOR_CHANGE_HUE
1226 const int BICOLOR_HUE_MAXDELTA = 40;
1227 int dh = delta-(val-cs.value())-(sat-cs.saturation());
1228 dh = qMin( BICOLOR_HUE_MAXDELTA, qAbs( dh ) ) * ( dh > 0 ? 1 : -1 );
1229 //int hue = qMin( 359, qMax( cs.hue() + delta-(val-cs.value())-(sat-cs.saturation()), 0 ) );
1230 //int hue = qMin( 359, qMax( cs.hue() + delta-(val-cs.value())-ds, 0 ) );
1231 int hue = cs.hue() + dh;
1232 if ( hue < 0 ) hue = 360 - hue;
1236 cs.setHsv( hue, sat, val );
1242 \brief Dump linear gradient to the string description.
1243 \param gradient linear gradient to be converted
1244 \return string representation of the linear gradient
1245 \sa stringToLinearGradient()
1247 QString Qtx::gradientToString( const QLinearGradient& gradient )
1251 data << QString::number( gradient.start().x() );
1252 data << QString::number( gradient.start().y() );
1253 data << QString::number( gradient.finalStop().x() );
1254 data << QString::number( gradient.finalStop().y() );
1255 switch( gradient.spread() )
1257 case QGradient::PadSpread:
1260 case QGradient::RepeatSpread:
1263 case QGradient::ReflectSpread:
1269 QGradientStops stops = gradient.stops();
1271 foreach ( stop, stops )
1273 data << QString::number( stop.first );
1274 data << colorToString( stop.second );
1276 return data.join( "|" );
1280 \brief Dump radial gradient to the string description.
1281 \param gradient radial gradient to be converted
1282 \return string representation of the radial gradient
1283 \sa stringToRadialGradient()
1285 QString Qtx::gradientToString( const QRadialGradient& gradient )
1289 data << QString::number( gradient.center().x() );
1290 data << QString::number( gradient.center().y() );
1291 data << QString::number( gradient.focalPoint().x() );
1292 data << QString::number( gradient.focalPoint().y() );
1293 data << QString::number( gradient.radius() );
1294 switch( gradient.spread() )
1296 case QGradient::PadSpread:
1299 case QGradient::RepeatSpread:
1302 case QGradient::ReflectSpread:
1308 QGradientStops stops = gradient.stops();
1310 foreach ( stop, stops )
1312 data << QString::number( stop.first );
1313 data << colorToString( stop.second );
1315 return data.join( "|" );
1319 \brief Dump conical gradient to the string description.
1320 \param gradient conical gradient to be converted
1321 \return string representation of the conical gradient
1322 \sa stringToConicalGradient()
1324 QString Qtx::gradientToString( const QConicalGradient& gradient )
1328 data << QString::number( gradient.center().x() );
1329 data << QString::number( gradient.center().y() );
1330 data << QString::number( gradient.angle() );
1331 switch( gradient.spread() )
1333 case QGradient::PadSpread:
1336 case QGradient::RepeatSpread:
1339 case QGradient::ReflectSpread:
1345 QGradientStops stops = gradient.stops();
1347 foreach ( stop, stops )
1349 data << QString::number( stop.first );
1350 data << colorToString( stop.second );
1352 return data.join( "|" );
1356 \brief Create linear gradient from its string representation.
1357 \param str string representation of the linear gradient
1358 \param gradient resulting linear gradient object
1359 \return \c true if the conversion is successful and \c false otherwise
1360 \sa gradientToString()
1362 bool Qtx::stringToLinearGradient( const QString& str, QLinearGradient& gradient )
1364 bool success = false;
1365 QStringList vals = str.split( "|", QString::SkipEmptyParts );
1366 if ( vals.count() > 4 && ( vals[0] == "linear" || vals[0] == "lg" ) )
1368 // start and end points
1369 double x1, y1, x2, y2;
1370 bool bOk1, bOk2, bOk3, bOk4;
1371 x1 = vals[1].toDouble( &bOk1 );
1372 y1 = vals[2].toDouble( &bOk2 );
1373 x2 = vals[3].toDouble( &bOk3 );
1374 y2 = vals[4].toDouble( &bOk4 );
1375 if ( bOk1 && bOk2 && bOk3 && bOk4 )
1377 gradient = QLinearGradient( x1, y1, x2, y2 );
1379 if ( vals.count() > 5 )
1381 QString spread = vals[ 5 ].trimmed().toLower();
1382 if ( spread == "pad" || spread == "0" )
1383 gradient.setSpread( QGradient::PadSpread );
1384 else if ( spread == "repeat" || spread == "2" )
1385 gradient.setSpread( QGradient::RepeatSpread );
1386 else if ( spread == "reflect" || spread == "1" )
1387 gradient.setSpread( QGradient::ReflectSpread );
1390 QGradientStops stops;
1391 for ( int i = 6; i < vals.count(); i+=2 )
1393 bool bOk5, bOk6 = false;
1395 double stop = vals[i].toDouble( &bOk5 );
1396 if ( i+1 < vals.count() )
1397 bOk6 = stringToColor( vals[ i+1 ], c );
1398 if ( bOk5 && stop >= 0.0 && stop <= 1.0 && bOk6 && c.isValid() )
1399 stops.append( QGradientStop( stop, c ) );
1401 gradient.setStops( stops );
1409 \brief Create radial gradient from its string representation.
1410 \param str string representation of the radial gradient
1411 \param gradient resulting radial gradient object
1412 \return \c true if the conversion is successful and \c false otherwise
1413 \sa gradientToString()
1415 bool Qtx::stringToRadialGradient( const QString& str, QRadialGradient& gradient )
1417 bool success = false;
1418 QStringList vals = str.split( "|", QString::SkipEmptyParts );
1419 if ( vals.count() > 5 && ( vals[0] == "radial" || vals[0] == "rg" ) )
1421 // center, radius and focal point
1422 double cx, cy, r, fx, fy;
1423 bool bOk1, bOk2, bOk3, bOk4, bOk5;
1424 cx = vals[1].toDouble( &bOk1 );
1425 cy = vals[2].toDouble( &bOk2 );
1426 fx = vals[3].toDouble( &bOk4 );
1427 fy = vals[4].toDouble( &bOk5 );
1428 r = vals[5].toDouble( &bOk3 );
1429 if ( bOk1 && bOk2 && bOk3 && bOk4 && bOk5 )
1431 gradient = QRadialGradient( cx, cy, r, fx, fy );
1433 if ( vals.count() > 6 )
1435 QString spread = vals[ 6 ].trimmed().toLower();
1436 if ( spread == "pad" || spread == "0" )
1437 gradient.setSpread( QGradient::PadSpread );
1438 else if ( spread == "repeat" || spread == "2" )
1439 gradient.setSpread( QGradient::RepeatSpread );
1440 else if ( spread == "reflect" || spread == "1" )
1441 gradient.setSpread( QGradient::ReflectSpread );
1444 QGradientStops stops;
1445 for ( int i = 7; i < vals.count(); i+=2 )
1447 bool bOk7, bOk8 = false;
1449 double stop = vals[i].toDouble( &bOk7 );
1450 if ( i+1 < vals.count() )
1451 bOk8 = stringToColor( vals[ i+1 ], c );
1452 if ( bOk7 && stop >= 0.0 && stop <= 1.0 && bOk8 && c.isValid() )
1453 stops.append( QGradientStop( stop, c ) );
1455 gradient.setStops( stops );
1463 \brief Create conical gradient from its string representation.
1464 \param str string representation of the conical gradient
1465 \param gradient resulting conical gradient object
1466 \return \c true if the conversion is successful and \c false otherwise
1467 \sa gradientToString()
1469 bool Qtx::stringToConicalGradient( const QString& str, QConicalGradient& gradient )
1471 bool success = false;
1472 QStringList vals = str.split( "|", QString::SkipEmptyParts );
1473 if ( vals.count() > 3 && ( vals[0] == "conical" || vals[0] == "cg" ) )
1477 bool bOk1, bOk2, bOk3;
1478 cx = vals[1].toDouble( &bOk1 );
1479 cy = vals[2].toDouble( &bOk2 );
1480 a = vals[3].toDouble( &bOk3 );
1481 if ( bOk1 && bOk2 && bOk3 )
1483 gradient = QConicalGradient( cx, cy, a );
1485 if ( vals.count() > 4 )
1487 QString spread = vals[ 4 ].trimmed().toLower();
1488 if ( spread == "pad" || spread == "0" )
1489 gradient.setSpread( QGradient::PadSpread );
1490 else if ( spread == "repeat" || spread == "2" )
1491 gradient.setSpread( QGradient::RepeatSpread );
1492 else if ( spread == "reflect" || spread == "1" )
1493 gradient.setSpread( QGradient::ReflectSpread );
1496 QGradientStops stops;
1497 for ( int i = 5; i < vals.count(); i+=2 )
1499 bool bOk4, bOk5 = false;
1501 double stop = vals[i].toDouble( &bOk4 );
1502 if ( i+1 < vals.count() )
1503 bOk5 = stringToColor( vals[ i+1 ], c );
1504 if ( bOk4 && stop >= 0.0 && stop <= 1.0 && bOk5 && c.isValid() )
1505 stops.append( QGradientStop( stop, c ) );
1507 gradient.setStops( stops );
1515 \brief Convert background data to the string representation.
1516 The resulting string consists of several sub-strings separated by ';' symbol.
1517 These sub-strings represent:
1518 1. background type (enumerator, see Qtx::BackgroundMode)
1519 2. texture image file name (string)
1520 3. texture mode (enumerator, see Qtx::TextureMode)
1521 4. "show texture" flag (boolean)
1522 5. first color (for simple gradient data) or solid color (for single-colored mode)
1523 6. second color (for simple gradient data)
1524 7. type of simple gradient (some integer identifier)
1525 8. complex gradient data (for custom gradient mode)
1526 Each sub-string consists of keyword/value couple, in form of "<keyword>=<value>".
1528 Backward conversion can be done with stringToBackground() method.
1530 \param bgData background data
1531 \return string representation of the background data
1533 \sa stringToBackground()
1535 QString Qtx::backgroundToString( const Qtx::BackgroundData& bgData )
1537 const QString dtSep = ";";
1538 const QString kwSep = "=";
1539 const QString kwBgType = "bt";
1540 const QString kwFileName = "fn";
1541 const QString kwTextureMode = "tm";
1542 const QString kwShowTexture = "ts";
1543 const QString kwFirstColor = "c1";
1544 const QString kwSecondColor = "c2";
1545 const QString kwGrType = "gt";
1546 const QString kwGrData = "gr";
1548 Qtx::BackgroundMode bgMode = bgData.mode();
1550 Qtx::TextureMode textureMode = bgData.texture( fileName );
1551 bool showTexture = bgData.isTextureShown();
1553 int gradientType = bgData.gradient( c1, c2 );
1554 const QGradient* gradient = bgData.gradient();
1557 switch ( gradient->type() ) {
1558 case QGradient::LinearGradient:
1559 grString = gradientToString( *(static_cast<const QLinearGradient*>( gradient )) );
1561 case QGradient::RadialGradient:
1562 grString = gradientToString( *(static_cast<const QRadialGradient*>( gradient )) );
1564 case QGradient::ConicalGradient:
1565 grString = gradientToString( *(static_cast<const QConicalGradient*>( gradient )) );
1572 data << QString( "%1%2%3" ).arg( kwBgType ).arg( kwSep ).arg( (int)bgMode );
1573 data << QString( "%1%2%3" ).arg( kwFileName ).arg( kwSep ).arg( fileName );
1574 data << QString( "%1%2%3" ).arg( kwTextureMode ).arg( kwSep ).arg( (int)textureMode );
1575 data << QString( "%1%2%3" ).arg( kwShowTexture ).arg( kwSep ).arg( showTexture ? "true" : "false" );
1576 data << QString( "%1%2%3" ).arg( kwFirstColor ).arg( kwSep ).arg( Qtx::colorToString( c1 ) );
1577 data << QString( "%1%2%3" ).arg( kwSecondColor ).arg( kwSep ).arg( Qtx::colorToString( c2 ) );
1578 data << QString( "%1%2%3" ).arg( kwGrType ).arg( kwSep ).arg( gradientType );
1579 data << QString( "%1%2%3" ).arg( kwGrData ).arg( kwSep ).arg( grString );
1581 return data.join( dtSep );
1585 \brief Restore background data from the string representation.
1587 The string should consist of several sub-strings separated by ';' symbol.
1588 Each sub-string consists of keyword/value couple, in form of "<keyword>=<value>".
1589 The sub-strings can follow in arbitrary order, some keywords can be missing.
1590 The background data is described by the following values:
1591 - background type (enumerator, see Qtx::BackgroundMode), keyword "bt"
1592 - texture image file name (string), keyword "fn"
1593 - texture mode (enumerator, see Qtx::TextureMode), keyword "tm"
1594 - "show texture" flag (boolean), keyword "ts"
1595 - first color (for simple gradient data) or solid color (for single-colored mode), keyword "c1"
1596 - second color (for simple gradient data), keyword "c2"
1597 - name of gradient type (string), keyword "gt"
1598 - complex gradient data (for custom gradient mode), keyword "gr"
1600 Also, for backward compatibility, background data can be represented by
1601 single color value, see stringToColor().
1603 Backward conversion can be done with backgroundToString() method.
1604 Returns invalid background if conversion could not be done.
1607 Qtx::BackgroundData bgData = Qtx::stringToBackground( str );
1608 if ( bgData.isValid() ) ) doSomething( bgData );
1611 \param theString string representation of the background data
1612 \return resulting background data (invalid if conversion has failed)
1614 \sa backgroundToString()
1617 Qtx::BackgroundData Qtx::stringToBackground( const QString& str )
1619 const QString dtSep = ";";
1620 const QString kwSep = "=";
1621 const QString kwBgType = "bt";
1622 const QString kwFileName = "fn";
1623 const QString kwTextureMode = "tm";
1624 const QString kwShowTexture = "ts";
1625 const QString kwFirstColor = "c1";
1626 const QString kwSecondColor = "c2";
1627 const QString kwGrType = "gt";
1628 const QString kwGrData = "gr";
1630 Qtx::BackgroundData bgData = BackgroundData();
1632 QStringList data = str.split( dtSep, QString::KeepEmptyParts );
1635 if ( data.count() == 1 && !data.contains( kwSep ) && stringToColor( data[0], c ) ) {
1636 // solid color mode, for backward compatibility
1637 bgData.setColor( c );
1640 QMap<QString, QString> dmap;
1642 foreach( QString d, data ) {
1643 QStringList items = d.split( kwSep, QString::KeepEmptyParts );
1644 if ( items.count() > 0 ) {
1645 QString kw = items.takeFirst().trimmed().toLower(); // keyword
1646 QString val = items.join( kwSep ).trimmed(); // if value contains "=" symbol, we have to restore it
1650 QString bgMode = dmap.value( kwBgType, QString() );
1651 QString fileName = dmap.value( kwFileName, QString() );
1652 QString textureMode = dmap.value( kwTextureMode, QString() );
1653 QString showTexture = dmap.value( kwShowTexture, QString() );
1654 QString color1 = dmap.value( kwFirstColor, QString() );
1655 QString color2 = dmap.value( kwSecondColor, QString() );
1656 QString gradientType = dmap.value( kwGrType, QString() );
1657 QString gradient = dmap.value( kwGrData, QString() );
1660 if ( !fileName.isEmpty() || !textureMode.isEmpty() || !showTexture.isEmpty() ) {
1661 Qtx::TextureMode m = (Qtx::TextureMode)( stringToInt( textureMode, Qtx::CenterTexture,
1662 Qtx::CenterTexture, Qtx::StretchTexture ) );
1663 bgData.setTexture( fileName, m );
1664 QStringList boolvars; boolvars << "true" << "yes" << "ok" << "1";
1665 if ( boolvars.contains( showTexture.trimmed().toLower() ) )
1666 bgData.setTextureShown( true );
1670 bool ok = Qtx::stringToColor( color1, c1 );
1672 bgData.setColor( c1 );
1674 // try simple gradient mode
1675 ok = Qtx::stringToColor( color2, c2 );
1676 if ( ok || !gradientType.isEmpty() ) {
1677 int gt = gradientType.toInt( &ok );
1678 bgData.setGradient( ok ? gt : -1, c1, c2 );
1680 // try custom gradient mode
1682 QConicalGradient cg;
1684 ok = Qtx::stringToLinearGradient( gradient, lg );
1686 bgData.setGradient( lg );
1688 ok = Qtx::stringToRadialGradient( gradient, rg );
1690 bgData.setGradient( rg );
1692 ok = Qtx::stringToConicalGradient( gradient, cg );
1694 bgData.setGradient( cg );
1697 // finally set background mode
1698 Qtx::BackgroundMode m = (Qtx::BackgroundMode)( stringToInt( bgMode, Qtx::ColorBackground,
1699 Qtx::NoBackground, Qtx::CustomGradientBackground ) );
1700 bgData.setMode( m );
1707 \class Qtx::Localizer
1708 \brief Localization helper
1710 This helper class can be used to solve the localization problems,
1711 usually related to the textual files reading/writing, namely when
1712 floating point values are read / written with API functions.
1713 The problem relates to such locale specific settings as decimal point
1714 separator, thousands separator, etc.
1716 To use the Localizer class, just create a local variable in the beginning
1717 of the code where you need to read / write data from textual file(s).
1718 The constructor of the class forces setting "C" locale temporariy.
1719 The destructor switches back to the initial locale.
1729 \brief Constructor. Forces "C" locale to be set.
1731 Qtx::Localizer::Localizer()
1733 myCurLocale = setlocale( LC_NUMERIC, 0 );
1734 setlocale( LC_NUMERIC, "C" );
1738 \brief Destructor. Reverts back to the initial locale.
1740 Qtx::Localizer::~Localizer()
1742 setlocale( LC_NUMERIC, myCurLocale.toLatin1().constData() );
1746 \class Qtx::BackgroundData
1747 \brief Stores background data
1749 This class is used to store background data. Depending on the mode,
1750 the background can be specified by:
1751 - image (by assigning the file name to be used as background texture), see setTexture(), setTextureShown()
1752 - single color (by assigning any color), see setColor()
1753 - simple two-color gradient (with the gradient type id and two colors), see setGradient( int, const QColor&, const QColor& )
1754 - complex gradient (by assigning arbitrary gradient data), see setGradient( const QGradient& )
1756 The class stores all the data passed to it, so switching between different modes can be done
1757 just by calling setMode() function.
1759 \note Texture is used with combination of the background mode.
1761 \note Two-color gradient is specified by two colors and integer identifier. The interpretation of
1762 this identifier should be done in the calling code.
1765 Qtx::BackgroundData bg;
1766 bg.setColor( QColor(100, 100, 100) ); // bg is switched to Qtx::ColorBackground mode
1767 bg.setGradient( Qt::Horizontal, Qt::gray, Qt::white ); // bg is switched to Qtx::ColorBackground mode
1768 QLinearGradient grad( 0,0,1,1 );
1769 grad.setColorAt( 0.0, Qt::gray );
1770 grad.setColorAt( 0.5, Qt::white );
1771 grad.setColorAt( 1.0, Qt::green );
1772 grad.setSpread( QGradient::PadSpread );
1773 bg.setGradient( grad ); // bg is switched to Qtx::CustomGradientBackground mode
1774 bg.setMode( Qtx::ColorBackground ); // bg is switched back to Qtx::ColorBackground mode
1775 bg.setTexture( "/data/images/background.png" ); // specify texture (in the centered mode by default)
1776 bg.setTextureShown( true ); // draw texture on the solid color background
1781 \brief Default constructor.
1782 Creates invalid background data.
1784 Qtx::BackgroundData::BackgroundData()
1785 : myTextureMode( Qtx::CenterTexture ), myGradientType( -1 ), myTextureShown( false )
1787 setMode( Qtx::NoBackground );
1792 Creates background data initialized with the specified color
1795 Qtx::BackgroundData::BackgroundData( const QColor& c )
1796 : myTextureMode( Qtx::CenterTexture ), myGradientType( -1 ), myTextureShown( false )
1803 Creates background data initialized with the specified two-color gradient
1804 \param type gradient type identifier
1805 \param c1 first gradient color
1806 \param c2 second gradient color
1807 \note the interpretation of the gradient identifier should be done in the calling code
1809 Qtx::BackgroundData::BackgroundData( int type, const QColor& c1, const QColor& c2 )
1810 : myTextureMode( Qtx::CenterTexture ), myGradientType( -1 ), myTextureShown( false )
1812 setGradient( type, c1, c2 );
1817 Creates background data initialized with the arbirtary gradient data
1818 \param grad gradient data
1820 Qtx::BackgroundData::BackgroundData( const QGradient& grad )
1821 : myTextureMode( Qtx::CenterTexture ), myGradientType( -1 ), myTextureShown( false )
1823 setGradient( grad );
1829 Qtx::BackgroundData::~BackgroundData()
1834 \brief Compares two background data objects
1836 bool Qtx::BackgroundData::operator==( const Qtx::BackgroundData& other ) const
1839 ( myMode == other.myMode ) &&
1840 ( myTextureMode == other.myTextureMode ) &&
1841 ( myFileName == other.myFileName ) &&
1842 ( myColors == other.myColors ) &&
1843 ( myGradientType == other.myGradientType ) &&
1844 ( myGradient == other.myGradient ) &&
1845 ( myTextureShown == other.myTextureShown );
1849 \brief Returns \c false if background data is not set (invalid)
1850 \return \c true if background data is valid or \c false otherwise
1853 bool Qtx::BackgroundData::isValid() const
1855 return myMode != Qtx::NoBackground;
1859 \brief Get background mode
1860 \return current background mode
1863 Qtx::BackgroundMode Qtx::BackgroundData::mode() const
1869 \brief Set background mode
1870 \param m background mode being set
1873 void Qtx::BackgroundData::setMode( const Qtx::BackgroundMode m )
1879 \brief Get file name used as a texture image
1880 \return path to the texture image file
1881 \sa setTexture(), setTextureShown()
1883 Qtx::TextureMode Qtx::BackgroundData::texture( QString& fileName ) const
1885 fileName = myFileName;
1886 return myTextureMode;
1890 \brief Set file name to be used as a texture image.
1892 \note To show texture image on the background it is necessary to call additionally
1893 setTextureShown() method.
1895 \param fileName path to the texture image file name
1896 \param m texture mode (Qtx::CenterTexture by default)
1897 \sa texture(), setTextureShown()
1899 void Qtx::BackgroundData::setTexture( const QString& fileName, const Qtx::TextureMode m )
1901 myFileName = fileName;
1906 \brief Check if "show texture" flag is switched on
1907 \return \c true if "show texture" flag is set or \c false otherwise
1908 \sa setTextureShown(), texture()
1910 bool Qtx::BackgroundData::isTextureShown() const
1912 return myTextureShown;
1916 \brief Specify if texture should be shown on the background or no.
1917 \param on \c true if texture should be shown or \c false otherwise
1918 \sa isTextureShown(), texture()
1920 void Qtx::BackgroundData::setTextureShown( bool on )
1922 myTextureShown = on;
1926 \brief Get background color. Returns null QColor if color is not set
1927 \return solid background color
1928 \sa setColor(), mode()
1930 QColor Qtx::BackgroundData::color() const
1932 return myColors.count() > 0 ? myColors[0] : QColor();
1936 \brief Set background color and switch to the Qtx::ColorBackground mode
1940 void Qtx::BackgroundData::setColor( const QColor& c )
1944 setMode( Qtx::ColorBackground );
1948 \brief Get simple gradient data.
1949 Returns -1 and null QColor for \a c1 and \a c2 if gradient data is not set
1950 \param c1 first gradient color is returned via this parameter
1951 \param c2 second gradient color is returned via this parameter
1952 \return current two-colored gradient mode type identifier
1953 \note the interpretation of the gradient identifier should be done in the calling code
1954 \sa setGradient(int, const QColor&, const QColor&), mode()
1956 int Qtx::BackgroundData::gradient( QColor& c1, QColor& c2 ) const
1958 c1 = myColors.count() > 0 ? myColors[0] : QColor();
1959 c2 = myColors.count() > 1 ? myColors[1] : ( myColors.count() > 0 ? myColors[0] : QColor() );
1960 return myGradientType;
1964 \brief Set simple background gradient data and switch to the Qtx::SimpleGradientBackground mode
1965 \param type two-colored gradient mode type identifier
1966 \param c1 first gradient color is returned via this parameter
1967 \param c2 second gradient color is returned via this parameter
1968 \note the interpretation of the gradient identifier should be done in the calling code
1969 \sa gradient(QColor&, QColor&), mode()
1971 void Qtx::BackgroundData::setGradient( int type, const QColor& c1, const QColor& c2 )
1974 myColors << c1 << c2;
1975 myGradientType = type;
1976 setMode( Qtx::SimpleGradientBackground );
1980 \brief Get complex gradient data.
1981 Returns QGradient of QGradient::NoGradient if gradient data is not set
1982 \note This function does not transform simple gradient data set with
1983 setGradient( const QString&, const QColor&, const QColor& ) to QGradient class
1984 \return gradient data
1985 \sa setGradient(const QGradient&), mode()
1987 const QGradient* Qtx::BackgroundData::gradient() const
1993 \brief Set complex background gradient data and switch to the Qtx::CustomGradientBackground mode
1994 \param grad gradient data (QLinearGradient, QRadialGradient or QConicalGradient)
1995 \sa gradient(), mode()
1997 void Qtx::BackgroundData::setGradient( const QGradient& grad )
2000 setMode( Qtx::CustomGradientBackground );
2004 \brief Convert string representation of version identifier to the numerical value.
2005 Resulting value can be used for comparison of different versions (lower, higher, equal).
2007 String representation of the version consists of zero or more components:
2009 [major[.minor[.release[patchid]]]]
2012 - major is version major number
2013 - minor is version minor number
2014 - release is version release number
2015 - patchid is a version dev identifier which is one of the following
2016 * 1 letter optionally followed by 1 or 2 digits, e.g. "a" for "alpha", "b1" for "beta 1"
2017 * "rc" optionally followed by 1 or 2 digits, e.g. "rc1" for "release candidate 1"
2018 * "dev" for development version (note: 7.4.0dev > 7.4.0, 7.4.0dev < 7.4.1, 7.4.0dev < 7.4.0a1)
2020 If version string does not include any component or has invalid format, the function returns 0.
2024 1.2.3a - version 1.2.3 alpha
2025 3.3.3b1 - version 3.3.3 beta 1
2026 7.4.0rc1 - version 7.4.0 release candidate 1
2027 7.4.0dev - dev version, i.e. future version 7.4.1 (or 7.5.0)
2029 \param version string representation of version
2030 \return numerical identifier of the version
2032 long Qtx::versionToId( const QString& version )
2036 QRegExp vers_exp( "^([0-9]+)([A-Z]|RC|DEV)?([0-9]{0,2})$", Qt::CaseInsensitive );
2038 QStringList vers = version.split( ".", QString::SkipEmptyParts );
2039 int major=0, minor=0;
2040 int release = 0, dev1 = 0, dev2 = 0;
2041 if ( vers.count() > 0 ) major = vers[0].toInt();
2042 if ( vers.count() > 1 ) minor = vers[1].toInt();
2043 if ( vers.count() > 2 ) {
2044 if ( vers_exp.indexIn( vers[2] ) != -1 ) {
2045 release = vers_exp.cap( 1 ).toInt();
2046 QString tag = vers_exp.cap( 2 ).toLower();
2047 if ( !tag.isEmpty() ) {
2048 // patchid is subtracted from version number
2049 // a = 55 --> -(55 * 100) + patch number --> 4500..4599, e.g. 7.4.1a1 -> 704004501
2050 // b = 54 --> -(54 * 100) + patch number --> 4600..4699, e.g. 7.4.1b1 -> 704004601
2051 // c = 53 --> -(53 * 100) + patch number --> 4700..4799, e.g. 7.4.1c1 -> 704004701
2053 // z = 30 --> -( 1 * 100) + patch number --> 7000..7099, e.g. 7.4.1z1 -> 704007001
2054 // rc = 1 --> -( 1 * 100) + patch number --> 9900..9999, e.g. 7.4.1rc1 -> 704009901
2055 // dev = -1 --> +( 1 * 100) + patch number --> 0100..0199, e.g. 7.4.1dev -> 704010100
2057 // i.e. "a" < "b" < ... < "z" < "rc" < [stable] < "dev"
2060 else if ( tag == "dev" )
2063 dev1 = (int)( QChar('z').toLatin1() ) - (int)( tag[ 0 ].toLatin1() ) + 30;
2065 if ( !vers_exp.cap( 3 ).isEmpty() )
2066 dev2 = vers_exp.cap( 3 ).toInt();
2070 int dev = dev1*100-dev2;
2073 id*=100; id+=release;
2081 \brief Get Qt installation directory
2083 The function tries to detect qt installation directory by analyzing the system variables in the following order:
2089 Optional parameter \a context allows obtaining subdirectory in the Qt installation directory.
2091 \param context optional sub-directory
2092 \return path to the Qt installation directory (or its sub-folder, if \a context is specified)
2095 QString Qtx::qtDir( const QString& context )
2097 const char* vars[] = { "QT5_ROOT_DIR", "QT4_ROOT_DIR", "QT_ROOT_DIR", "QTDIR" };
2099 for (uint i = 0; i < sizeof(vars)/sizeof(vars[0]) && qtPath.isEmpty(); i++ )
2100 qtPath = qgetenv( vars[i] );
2101 if ( !qtPath.isEmpty() && !context.isEmpty() )
2102 qtPath = QDir( qtPath ).absoluteFilePath( context );
2107 Creates font from string description
2109 QFont Qtx::stringToFont( const QString& fontDescription )
2112 if ( fontDescription.trimmed().isEmpty() || !font.fromString( fontDescription ) )
2113 font = QFont( "Courier", 11 );
2117 #if !defined WIN32 && !defined __APPLE__
2119 #include <X11/Xlib.h>
2123 \brief Open the default X display and returns pointer to it.
2124 This method is available on Linux only.
2125 \return Pointer to X display.
2128 void* Qtx::getDisplay()
2130 static Display* pDisplay = NULL;
2132 pDisplay = XOpenDisplay( NULL );
2137 \brief Returns pointer to X visual suitable for 3D rendering.
2138 This method is available on Linux only.
2139 \return Pointer to X visual.
2142 Qt::HANDLE Qtx::getVisual()
2144 Qt::HANDLE res = (Qt::HANDLE)NULL;
2146 Display* pDisplay = (Display*)getDisplay();
2153 // Make sure OpenGL's GLX extension supported
2154 if( !glXQueryExtension( pDisplay, &errorBase, &eventBase ) ){
2155 qCritical( "Could not find glx extension" );
2159 // Find an appropriate visual
2161 int doubleBufferVisual[] = {
2162 GLX_RGBA, // Needs to support OpenGL
2163 GLX_DEPTH_SIZE, 16, // Needs to support a 16 bit depth buffer
2164 GLX_DOUBLEBUFFER, // Needs to support double-buffering
2165 GLX_STEREO, // Needs to support stereo rendering
2166 GLX_STENCIL_SIZE, 1,
2170 // Try for the double-bufferd visual first
2171 XVisualInfo *visualInfo = NULL;
2172 visualInfo = glXChooseVisual( pDisplay, DefaultScreen(pDisplay), doubleBufferVisual );
2174 if( visualInfo == NULL ){
2175 qCritical( "Could not find matching glx visual" );
2179 qDebug() << "Picked visual 0x" << hex << XVisualIDFromVisual( visualInfo->visual );
2180 res = (Qt::HANDLE)( visualInfo->visual );
2188 #if QT_VERSION > QT_VERSION_CHECK(5, 0, 0)
2190 \brief Set default QSurfaceFormat for an application.
2192 This application property should be set before a creation of the QApplication.
2194 void Qtx::initDefaultSurfaceFormat()
2196 // Settings from Paraview:
2197 // This piece of code was taken from QVTKOpenGLWidget::defaultFormat() method in
2198 // order to avoid dependency of the SALOME_Session_Server on vtk libraries
2200 fmt.setRenderableType(QSurfaceFormat::OpenGL);
2201 fmt.setVersion(3, 2);
2202 fmt.setProfile(QSurfaceFormat::CoreProfile);
2203 fmt.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
2204 fmt.setRedBufferSize(1);
2205 fmt.setGreenBufferSize(1);
2206 fmt.setBlueBufferSize(1);
2207 fmt.setDepthBufferSize(1);
2208 fmt.setStencilBufferSize(0);
2209 fmt.setAlphaBufferSize(1);
2210 fmt.setStereo(false);
2213 // Settings for OCCT viewer window:
2214 fmt.setDepthBufferSize(16);
2215 fmt.setStencilBufferSize(1);
2216 // fmt.setProfile(QSurfaceFormat::CompatibilityProfile);
2218 QSurfaceFormat::setDefaultFormat(fmt);
2223 \class Qtx::CmdLineArgs
2224 \brief Get access to the command line arguments in the C-like manner.
2226 This class translates command line arguments stored in QApplication in form of QStrlingList
2227 to the char* array, in the same way as they specified to main() function.
2229 Constructor of class allocates required memory to store arguments; destructor deallocates it,
2230 This allows using this class as a local variable:
2233 Qtx::CmdLineArgs args;
2234 some_function(args.argc(), args.argv()); // function that has main()-like syntax.
2239 \brief Default constructor.
2241 Qtx::CmdLineArgs::CmdLineArgs()
2243 QStringList args = QCoreApplication::arguments();
2244 myArgc = args.size();
2245 myArgv = new char*[myArgc];
2246 for ( int i = 0; i < myArgc; i++ ) {
2247 QByteArray ba = args[i].toUtf8();
2248 myArgv[i] = qstrdup(ba.constData());
2253 \brief Destructor. Deallocates the array with command line arguments
2255 Qtx::CmdLineArgs::~CmdLineArgs()
2257 for ( int i = 0; i < myArgc; i++ )
2263 \brief Get number of command line arguments
2264 \return number of arguments
2266 int Qtx::CmdLineArgs::argc() const
2272 \brief Get command line arguments
2273 \return command line arguments
2275 char** Qtx::CmdLineArgs::argv() const