1 // Copyright (C) 2007-2022 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 #include <QSurfaceFormat>
50 #define MAX_VALUE_SIZE 32767 // Limit according to http://msdn.microsoft.com/en-us/library/ms683188.aspx
55 #define BICOLOR_CHANGE_HUE
58 \brief Auxiliary function converting string \a str to the integer value.
59 Parameter \a defVal specifies default value that is returned if conversion can't be done.
60 Parameters \a minVal and \a maxVal limit the resulting value.
61 \param str string being converted
62 \param defVal default value
63 \param minVal minimum allowed value
64 \param maxVal maximum allowed value
65 \return integer value obtained from the string
68 static int stringToInt( const QString& str, int defVal, int minVal, int maxVal )
71 int v = str.toInt( &ok );
72 if ( !ok ) v = defVal;
73 return qMin( qMax( v, minVal ), maxVal );
78 \brief A set of helpful utility functions.
80 The class implements a set of the static functions which can be used
81 for the different purposes:
82 - specify tab order for the set of widgets: setTabOrder()
83 - align one widget to the coordinates of the another one: alignWidget()
84 - remove extra separators from the menu or toolbar: simplifySeparators()
85 - retrieve directory, file name and extension parts of the path:
86 dir(), file(), extension()
87 - get the path to the temporary directory: tmpDir()
88 - create or remove a directory (recursively): mkDir(), rmDir()
89 - convert text file from DOS to UNIX native format: dos2unix()
90 - convert a picture to the gray scale: grayscale()
95 \brief Convert character array (ASCII string) to the QString.
96 \param str character array
97 \param len array length, if < 0, the array should be zero-terminated
98 \return QString object
100 QString Qtx::toQString( const char* str, const int len )
102 return toQString( (unsigned char*)str, len );
106 \brief Convert integer array (UNICODE string) to the QString.
107 \param str integer array
108 \param len array length, if < 0, the array should be zero-terminated
109 \return QString object
111 QString Qtx::toQString( const short* str, const int len )
113 return toQString( (unsigned short*)str, len );
117 \brief Convert character array (ASCII string) to the QString.
118 \param str character array
119 \param len array length, if < 0, the array should be zero-terminated
120 \return QString object
122 QString Qtx::toQString( const unsigned char* str, const int len )
125 const unsigned char* s = str;
126 while ( len < 0 || res.length() < len )
131 res.append( QChar( *s ) );
138 \brief Convert integer array (UNICODE string) to the QString.
139 \param str integer array
140 \param len array length, if < 0, the array should be zero-terminated
141 \return QString object
143 QString Qtx::toQString( const unsigned short* str, const int len )
146 const unsigned short* s = str;
147 while ( len < 0 || res.length() < len )
152 res.append( QChar( *s ) );
159 \brief Set tab order for specified list of widgets.
161 The function has arbitrary number of parameters, each should be
162 hovewer of QWidget* type. Last parameter should be null pointer.
164 \param first first widget in the sequence
166 void Qtx::setTabOrder( QWidget* first, ... )
169 va_start( wids, first );
173 QWidget* cur = first;
176 widList.append( cur );
177 cur = va_arg( wids, QWidget* );
180 setTabOrder( widList );
184 \brief Set tab order for specified list of widgets.
185 \param widgets list of widgets
187 void Qtx::setTabOrder( const QWidgetList& widgets )
189 if ( widgets.count() < 2 )
193 for ( QWidgetList::const_iterator it = widgets.begin(); it!= widgets.end(); ++it )
197 QWidget::setTabOrder( prev, next );
203 \brief Align widget \a src relative to widget \a ref acording to the
204 alignment flags \a alignFlags.
205 \param src source widget (being aligned)
206 \param ref reference widget (source widget being aligned to)
207 \param alignFlags alignment flags (Qtx::AlignmentFlags)
209 void Qtx::alignWidget( QWidget* src, const QWidget* ref, const int alignFlags )
211 if ( !src || !ref || !alignFlags )
214 QPoint srcOri = src->pos();
215 QPoint refOri = ref->pos();
216 if ( src->parentWidget() && !src->isTopLevel() )
217 srcOri = src->parentWidget()->mapToGlobal( srcOri );
218 if ( ref->parentWidget() && !ref->isTopLevel() )
219 refOri = ref->parentWidget()->mapToGlobal( refOri );
221 int x = srcOri.x(), y = srcOri.y();
222 int refWidth = ref->frameGeometry().width(), refHei = ref->frameGeometry().height();
223 int srcWidth = src->frameGeometry().width(), srcHei = src->frameGeometry().height();
226 srcWidth = src->sizeHint().width();
228 srcHei = src->sizeHint().height();
231 if ( ref->isTopLevel() && ref->isMaximized() &&
232 src->isTopLevel() && !src->isMaximized() )
233 border = ( src->frameGeometry().width() - src->width() ) / 2;
235 if ( alignFlags & Qtx::AlignLeft )
236 x = refOri.x() + border;
237 if ( alignFlags & Qtx::AlignOutLeft )
238 x = refOri.x() - srcWidth - border;
239 if ( alignFlags & Qtx::AlignRight )
240 x = refOri.x() + refWidth - srcWidth - border;
241 if ( alignFlags & Qtx::AlignOutRight )
242 x = refOri.x() + refWidth + border;
243 if ( alignFlags & Qtx::AlignTop )
244 y = refOri.y() + border;
245 if ( alignFlags & Qtx::AlignOutTop )
246 y = refOri.y() - srcHei - border;
247 if ( alignFlags & Qtx::AlignBottom )
248 y = refOri.y() + refHei - srcHei - border;
249 if ( alignFlags & Qtx::AlignOutBottom )
250 y = refOri.y() + refHei + border;
251 if ( alignFlags & Qtx::AlignHCenter )
252 x = refOri.x() + ( refWidth - srcWidth ) / 2;
253 if ( alignFlags & Qtx::AlignVCenter )
254 y = refOri.y() + ( refHei - srcHei ) / 2;
256 if ( src->parentWidget() && !src->isTopLevel() )
258 QPoint pos = src->parentWidget()->mapFromGlobal( QPoint( x, y ) );
263 QWidget* desk = QApplication::desktop();
264 if ( desk && x + srcWidth + border > desk->width() )
265 x = desk->width() - srcWidth - border;
266 if ( desk && y + srcHei + border > desk->height() )
267 y = desk->height() - srcHei - border;
276 \brief Remove (recursively) unnecessary separators from the menu or toolbar.
277 \param wid widget, should be of QMenu* or QToolBar* class
279 void Qtx::simplifySeparators( QWidget* wid, const bool recursive )
284 if ( wid->inherits( "QMenu") || wid->inherits( "QMenuBar") )
286 if ( qobject_cast<QMenu*>( wid ) )
287 qobject_cast<QMenu*>( wid )->setSeparatorsCollapsible( true );
290 foreach ( QAction* action, wid->actions() )
292 if ( action->menu() )
293 simplifySeparators( action->menu(), recursive );
299 QList<QAction*> actions = wid->actions();
300 if ( actions.isEmpty() )
303 bool is_action = false;
304 for ( int i = 0; i < actions.count(); i++ )
306 QAction* action = actions[i];
307 if ( action->isSeparator() )
309 action->setVisible( is_action );
312 else if ( action->isVisible() )
318 for ( int i = actions.count() - 1; i > 0; i-- )
320 QAction* action = actions[i];
321 if ( action->isSeparator() )
323 action->setVisible( is_action );
326 else if ( action->isVisible() )
335 \brief Return \c true if specified \a parent is a parent object
336 of given \a child (in terms of QObject).
338 This function works recursively. It means that \a true is also
339 returned if \a parent is a grand-father, grand-grand-father, etc
340 of \a child. If the same object is given as both \a parent and
341 \a child, \c true is also returned.
343 \param child child object
344 \param parent parent object
345 \return \c true if the \a parent is a parent of \a child
347 bool Qtx::isParent( QObject* child, QObject* parent )
349 if ( !child || !parent )
353 QObject* obj = child;
354 while ( !res && obj )
363 \brief Find the parent object of class specified by \a className (in terms of QObject).
365 \param obj current object
366 \param className class name of the parent
367 \return parent object or null pointer if the parent not found
369 QObject* Qtx::findParent( QObject* obj, const char* className )
374 if ( !className || !strlen( className ) )
375 return obj->parent();
378 QObject* p = obj->parent();
381 if ( p->inherits( className ) )
390 \brief Return directory part of the file path.
392 If the file path does not include directory part (the file is in the
393 current directory), null string is returned.
395 \param path file path
396 \param abs if true (default) \a path parameter is treated as absolute file path
397 \return directory part of the file path
399 QString Qtx::dir( const QString& path, const bool abs )
401 QDir aDir = QFileInfo( path ).dir();
402 QString dirPath = abs ? aDir.absolutePath() : aDir.path();
403 if ( dirPath == QString( "." ) )
409 \brief Return file name part of the file path.
411 \param path file path
412 \param withExt if true (default) complete file name (with all
413 extension except the last) is returned, otherwise only base name
415 \return file name part of the file path
417 QString Qtx::file( const QString& path, bool withExt )
419 QString fPath = path;
420 while ( !fPath.isEmpty() && ( fPath[fPath.length() - 1] == '\\' || fPath[fPath.length() - 1] == '/' ) )
421 fPath.remove( fPath.length() - 1, 1 );
424 return QFileInfo( fPath ).fileName();
426 return QFileInfo( fPath ).completeBaseName();
430 \brief Return extension part of the file path.
432 \param path file path
433 \param full if true complete extension (all extensions, dot separated)
434 is returned, otherwise (default) only last extension is returned
435 \return extension part of the file path
437 QString Qtx::extension( const QString& path, const bool full )
439 return full ? QFileInfo( path ).completeSuffix() : QFileInfo( path ).suffix();
443 \brief Convert the given parameter to the platform-specific library name.
445 The function appends platform-specific prefix (lib) and suffix (.dll/.so)
446 to the library file name.
447 For example, if \a str = "mylib", "libmylib.so" is returned for Linux and
448 mylib.dll for Windows.
450 \param str short library name
451 \return full library name
453 QString Qtx::library( const QString& str )
455 QString path = dir( str, false );
456 QString name = file( str, false );
457 QString ext = extension( str );
460 if ( !name.startsWith( "lib" ) )
461 name = QString( "lib" ) + name;
465 QString libExt( "dll" );
466 #elif defined(__APPLE__)
467 QString libExt( "dylib" );
469 QString libExt( "so" );
472 if ( ext.toLower() != QString( "so" ) && ext.toLower() != QString( "dll" ) && ext.toLower() != QString( "dylib" ) )
474 if ( !name.isEmpty() && !ext.isEmpty() )
475 name += QString( "." );
481 QString fileName = addSlash( path ) + name + QString( "." ) + ext;
487 \brief Get the temporary directory name.
488 \return temporary directory (platform specific)
490 QString Qtx::tmpDir()
492 QString tmpdir = getenv( "TEMP" );
493 if ( tmpdir.isEmpty() )
494 tmpdir = getenv ( "TMP" );
495 if ( tmpdir.isEmpty() )
498 tmpdir = QString("C:\\");
500 tmpdir = QString("/tmp");
507 \brief Create directory recursively including all intermediate sub directories.
508 \return \c true if the directory is successfully created and \c false otherwise
510 bool Qtx::mkDir( const QString& dirPath )
512 return QDir().mkpath( dirPath );
516 \brief Remove directory recursively including all subdirectories and files.
517 \return \c true if the directory is successfully removed and \c false otherwise
519 bool Qtx::rmDir( const QString& thePath )
521 QFileInfo fi( thePath );
527 stat = QFile::remove( thePath );
528 else if ( fi.isDir() )
530 QDir aDir( thePath );
531 QFileInfoList anEntries = aDir.entryInfoList();
532 for ( QFileInfoList::iterator it = anEntries.begin(); it != anEntries.end(); ++it )
535 if ( inf.fileName() == "." || inf.fileName() == ".." )
537 stat = stat && rmDir( inf.absoluteFilePath() );
539 stat = stat && aDir.rmdir( thePath );
545 \brief Add a slash (platform-specific) to the end of \a path
546 if it is not already there.
547 \param path directory path
548 \return modified path (with slash added to the end)
550 QString Qtx::addSlash( const QString& path )
553 if ( !res.isEmpty() && res.at( res.length() - 1 ) != QChar( '/' ) &&
554 res.at( res.length() - 1 ) != QChar( '\\' ) )
555 res += QDir::separator();
560 \brief Convert text file from DOS format to UNIX.
562 The function replaces "LF/CR" symbols sequence by "LF" symbol.
564 \param absName file name
565 \return \c true if the file is converted successfully and \c false in
568 bool Qtx::dos2unix( const QString& absName )
570 FILE* src = ::fopen( absName.toUtf8(), "rb" );
574 /* we'll use temporary file */
575 char temp[512] = { '\0' };
576 QString dir = Qtx::dir( absName );
577 FILE* tgt = ::fopen( strcpy( temp, ::tempnam( dir.toUtf8(), "__x" ) ), "wb" );
581 /* temp -> result of conversion */
582 const char CR = 0x0d;
583 const char LF = 0x0a;
584 bool waitingLF = false;
589 char inbuf[512], outbuf[512];
592 int nbread = (int)::fread( inbuf, 1, sizeof( inbuf ), src ); //!< TODO: conversion from 'size_t' to 'int'
593 for ( int incnt = 0; incnt < nbread; incnt++ )
598 if ( inbuf[incnt] == LF )
599 outbuf[outcnt++] = LF;
601 outbuf[outcnt++] = CR;
603 else if ( inbuf[incnt] == CR )
606 outbuf[outcnt++] = inbuf[incnt];
609 /* check last sym in buffer */
610 waitingLF = ( inbuf[nbread - 1] == CR );
612 /* write converted buffer to temp file */
613 int nbwri = (int)::fwrite( outbuf, 1, outcnt, tgt ); //!< TODO: conversion from 'size_t' to 'int'
614 if ( nbwri != outcnt )
618 QFile::remove( QString( temp ) );
621 if ( nbread != sizeof( inbuf ) )
622 break; /* converted ok */
627 /* rename temp -> src */
628 if ( !QFile::remove( absName ) )
631 return QDir().rename( QString( temp ), absName );
635 \brief Create path completer which can be used in the widgets
636 to provide auto completions.
638 Create an instance of QCompleter class and returns the pointer on it.
639 The calling function is responsible to the desstroying of the created
642 The QCompleter class provides completions based on a item model and can be
643 used in such as QLineEdit and QComboBox.
644 When the user starts typing a word, QCompleter suggests possible ways of
645 completing the word, based on a word list.
647 \param type path type (Qtx::PathType)
648 \param filter file/directory filters (list of wildcards, separated by ";;")
649 \return a pointer to the created completer
651 QCompleter* Qtx::pathCompleter( const PathType type, const QString& filter )
654 QStringList filterList = filter.split( ";;" );
655 for ( QStringList::const_iterator it = filterList.begin(); it != filterList.end(); ++it )
657 QRegExp rx( "[\\s\\w,;]*\\(?\\*\\.([\\w]+)\\)?[\\d\\s\\w]*" );
659 while ( ( index = rx.indexIn( *it, index ) ) != -1 )
661 extList.append( QString( "*.%1" ).arg( rx.cap( 1 ) ) );
662 index += rx.matchedLength();
666 QDir::Filters filters = 0;
671 filters = QDir::AllEntries | QDir::AllDirs | QDir::NoDotAndDotDot;
674 filters = QDir::Drives | QDir::Dirs | QDir::NoDotAndDotDot;
678 QDirModel* dm = new QDirModel( extList, filters, QDir::Unsorted );
679 QCompleter* cmp = new QCompleter( dm, 0 );
680 dm->setParent( cmp );
686 \brief Parse given string to retrieve environment variable.
688 Looks through the string for the environment variable patterns.
689 If string contains variable satisfying any pattern, the variable name
690 is returned, start index of the variable is returned in the \a start parameter,
691 and length of the variable is returned in the \a len parameter.
693 Supported environment variables definitions:
694 - ${name} or $name : Linux shell variable
695 - $(name) : GNU make substitution
696 - %name% : Windows shell variable
697 - %(name)s : Python substitutions:
699 \param str string being processed
700 \param start if variable is found, this parameter contains its starting
701 position in the \a str
702 \param len if variable is found, this parameter contains its length
703 \return first found variable or null QString if there is no ones
705 QString Qtx::findEnvVar( const QString& str, int& start, int& len )
711 rxList << "\\$\\{([a-zA-Z][a-zA-Z_0-9]*)\\}"; // ${name}
712 rxList << "\\$([a-zA-Z][a-zA-Z_0-9]*)"; // $name
713 rxList << "\\$\\(([a-zA-Z][a-zA-Z_0-9]*)\\)"; // $(name)
714 rxList << "%([a-zA-Z][a-zA-Z0-9_]*)%"; // %name%
715 rxList << "%\\(([a-zA-Z][a-zA-Z_0-9]*)\\)s"; // %(name)s
717 for ( int i = 0; i < rxList.count() && varName.isEmpty(); ++i )
719 QRegExp rx(rxList[i]);
720 int pos = rx.indexIn( str, start );
723 varName = rx.cap( 1 );
725 len = rx.matchedLength();
732 \brief Substitute environment variables by their values.
734 Environment variable is substituted by its value.
736 \param str string to be processed
737 \return processed string (with all substitutions made)
739 QString Qtx::makeEnvVarSubst( const QString& str, const SubstMode mode )
744 QMap<QString, int> ignoreMap;
746 int start( 0 ), len( 0 );
749 QString envName = findEnvVar( res, start, len );
750 if ( envName.isNull() )
754 if ( getenv( envName ).isEmpty() || mode == Always )
755 newStr = QString( getenv( envName ) );
757 if ( newStr.isNull() )
759 if ( ignoreMap.contains( envName ) )
764 ignoreMap.insert( envName, 0 );
766 res.replace( start, len, newStr );
769 res.replace( "$$", "$" );
770 res.replace( "%%", "%" );
777 \brief Pack the specified color into integer RGB set.
778 \param c unpacked color
781 int Qtx::rgbSet( const QColor& c )
783 return rgbSet( c.red(), c.green(), c.blue() );
787 \brief Pack the specified RGB color components into integer RGB set.
788 \param r red component
789 \param g green component
790 \param b blue component
793 int Qtx::rgbSet( const int r, const int g, const int b )
795 return ( ( ( 0xff & r ) << 16 ) + ( ( 0xff & g ) << 8 ) + ( 0xff & b ) );
799 \brief Unpack the specified integer RGB set to the color.
800 \param rgb packed color
801 \return unpacked color (QColor)
803 QColor Qtx::rgbSet( const int rgb )
806 rgbSet( rgb, r, g, b );
807 return QColor( r, g, b );
811 \brief Unpack the specified integer RGB set to the three RGB components.
812 \param rgb packed color
813 \param r returned unpacked red component
814 \param g returned unpacked green component
815 \param b returned unpacked blue component
817 void Qtx::rgbSet( const int rgb, int& r, int& g, int& b )
819 r = ( rgb >> 16 ) & 0xff;
820 g = ( rgb >> 8 ) & 0xff;
825 \brief Return the color specified by the index between min (blue) and max (red).
826 \param index color index
827 \param min required minimum hue value
828 \param max required maximum hue value
829 \return resulting color
831 QColor Qtx::scaleColor( const int index, const int min, const int max )
833 static const int HUE[10] = {230, 210, 195, 180, 160, 80, 60, 50, 30, 0};
839 double aPosition = 9.0 * ( index - min ) / ( max - min );
840 if ( aPosition > 0.0 )
842 if ( aPosition >= 9.0 )
846 int idx = (int)aPosition;
847 hue = HUE[idx] + int( ( aPosition - idx ) * ( HUE[idx + 1] - HUE[idx] ) );
852 return QColor::fromHsv( hue, 255, 255 );
856 \brief Generate required number of colors aligned from blue to red.
857 \param num required number of colors
858 \param lst returned set of colors
860 void Qtx::scaleColors( const int num, QColorList& lst )
863 for ( int i = 0; i < num; i++ )
864 lst.append( scaleColor( i, 0, num - 1 ) );
868 \brief Scale the pixmap to the required size.
870 If \a h is 0 (default) the value of \a w is used instead (to create
873 \param icon pixmap to be resized
874 \param w required pixmap width
875 \param h required pixmap height
876 \return scaled pixmap
878 QPixmap Qtx::scaleIcon( const QPixmap& icon, const unsigned w, const unsigned h )
881 int aw = w, ah = h <= 0 ? w : h;
882 if ( icon.isNull() || aw <= 0 || ah <= 0 || ( aw == icon.width() && ah == icon.height() ) )
885 p = icon.fromImage( icon.toImage().scaled( aw, ah, Qt::KeepAspectRatio, Qt::SmoothTransformation ) );
890 \brief Convert given image to the grayscale format.
891 \param img initial image
892 \return converted to the grayscale image
894 QImage Qtx::grayscale( const QImage& img )
898 int colNum = res.colorCount();
901 for ( int i = 0; i < colNum; i++ )
902 res.setColor( i, qGray( res.color( i ) ) );
906 for ( int y = 0; y < res.height(); y++ )
908 for ( int x = 0; x < res.width(); x++ )
910 QRgb pix = res.pixel( x, y );
911 res.setPixel( x, y, qRgba( qGray( pix ), qGray( pix ), qGray( pix ), qAlpha( pix ) ) );
920 \brief Convert given pixmap to the grayscale format.
921 \param pix initial pixmap
922 \return converted to the grayscale pixmap
924 QPixmap Qtx::grayscale( const QPixmap& pix )
927 res.fromImage( grayscale( pix.toImage() ) );
932 \brief Create transparent image.
933 \param w required image width
934 \param h required image height
935 \param d required image depth
936 \return generated image
938 QImage Qtx::transparentImage( const int w, const int h, const int d )
944 fmt = QImage::Format_Mono;
947 fmt = QImage::Format_Indexed8;
953 fmt = QImage::Format_ARGB32;
957 QImage img( w, h, fmt );
960 // img.setAlphaBuffer( true );
961 for ( int i = 0; i < img.height(); i++ )
962 for ( int j = 0; j < img.width(); j++ )
963 img.setPixel( j, i, qRgba( 0, 0, 0, 0 ) );
969 \brief Create transparent pixmap.
970 \param w required image width
971 \param h required pixmap height
972 \param d required pixmap depth
973 \return generated pixmap
975 QPixmap Qtx::transparentPixmap( const int w, const int h, const int d )
978 QImage img = transparentImage( w, h, d );
980 pix.fromImage( img );
985 \brief Create composite pixmap.
987 Pixmap \a pix is drawn over pixmap \a dest with coordinates
988 specified relatively to the upper left corner of \a dest.
989 If \a dest is not given, the new empty pixmap with appropriate size created instead.
991 \param pix source pixmap
992 \param x horizontal shift
993 \param y vertical shift
994 \param dest background pixmap
995 \return resulting pixmap
997 QPixmap Qtx::composite( const QPixmap& pix, const int x, const int y, const QPixmap& dest )
1002 int width = qMax( pix.width() + x, dest.width() );
1003 int height = qMax( pix.height() + y, dest.height() );
1005 QPixmap res( width, height );
1006 QImage img = transparentImage( width, height, 32 );
1010 p.fillRect( 0, 0, width, height, QBrush( Qt::white ) );
1012 if ( !dest.isNull() )
1014 p.drawPixmap( 0, 0, dest );
1015 QImage temp = dest.toImage();
1016 for ( int i = 0; i < temp.width() && i < img.width(); i++ )
1018 for ( int j = 0; j < temp.height() && j < img.height(); j++ )
1020 if ( temp.hasAlphaChannel() )
1021 img.setPixel( i, j, temp.pixel( i, j ) );
1024 QRgb p = temp.pixel( i, j );
1025 img.setPixel( i, j, qRgba( qRed( p ), qGreen( p ), qBlue( p ), 255 ) );
1031 p.drawPixmap( x, y, pix );
1032 QImage temp = pix.toImage();
1033 for ( int c = x; c < temp.width() + x && c < img.width(); c++ )
1035 for ( int r = y; r < temp.height() + y && r < img.height(); r++ )
1037 if ( qAlpha( temp.pixel( c - x, r - y ) ) > 0 )
1038 img.setPixel( c, r, temp.pixel( c - x, r - y ) );
1044 for ( int ai = 0; ai < img.width(); ai++ )
1046 for ( int aj = 0; aj < img.height(); aj++ )
1048 if ( qAlpha( img.pixel( ai, aj ) ) < 1 )
1049 img.setPixel( ai, aj, qRgba( 255, 255, 255, 255 ) );
1051 img.setPixel( ai, aj, qRgba( 0, 0, 0, 0 ) );
1055 QBitmap bmp( width, height );
1056 bmp.fromImage( img, Qt::ColorMode_Mask | Qt::ThresholdDither );
1063 \brief Convert color to the string representation.
1065 The resulting string is in the one of two possible formats
1066 (\c RR, \c GG, \c BB and \c AA value represent red, green, blue
1067 and alpha components of the color):
1068 - if color has alpha channel : "#RR,#GG,#BB,#AA"
1069 - if color does not have alpha channel : "#RRGGBB"
1071 If color is invalid, null string is returned.
1073 Backward conversion can be done with stringToColor() method.
1075 \param color color to be converted
1076 \return string representation of the color
1080 QString Qtx::colorToString( const QColor& color )
1083 if ( color.isValid() )
1085 if ( color.alpha() != 255 )
1088 vals << QString( "#%1" ).arg( color.red(), 0, 16 );
1089 vals << QString( "#%1" ).arg( color.green(), 0, 16 );
1090 vals << QString( "#%1" ).arg( color.blue(), 0, 16 );
1091 vals << QString( "#%1" ).arg( color.alpha(), 0, 16 );
1092 str = vals.join( "," );
1103 \brief Create color from the string representation.
1105 The parameter \a str must be in the one of following formats
1106 (\c RR, \c GG, \c BB and \c AA value represent red, green, blue
1107 and alpha components of the color):
1108 - "#RR,#GG,#BB[,#AA]" or "#RR #GG #BB[ #AA]" (\c RR, \c GG, \c BB
1109 and optional \c AA values represent red, green, blue and alpha
1110 components of the color in hexadecimal form)
1111 - "RR,GG,BB[,AA]" or "RR GG BB[ AA]" (\c RR, \c GG, \c BB
1112 and optional \c AA values represent red, green, blue and alpha
1113 components of the color in decimal form)
1114 - "#RRGGBB" - (\c RR, \c GG and \c BB values represent red, green and blue
1115 components of the color in hexadecimal form)
1116 - an integer value representing packed color components (see rgbSet())
1117 - a name from the list of colors defined in the list of SVG color keyword names
1118 provided by the World Wide Web Consortium; for example, "steelblue" or "gainsboro".
1120 Backward conversion can be done with colorToString() method.
1122 \param str string representation of the color
1123 \param color resulting color value
1124 \return \c true if the conversion is successful and \c false otherwise
1126 \sa colorToString(), rgbSet()
1128 bool Qtx::stringToColor( const QString& str, QColor& color )
1131 QStringList vals = str.split( QRegExp( "[\\s|,]" ), QString::SkipEmptyParts );
1134 for ( QStringList::const_iterator it = vals.begin(); it != vals.end() && res; ++it )
1137 if ( (*it).startsWith( "#" ) )
1138 num = (*it).mid( 1 ).toInt( &res, 16 );
1140 num = (*it).toInt( &res, 10 );
1145 res = res && nums.count() >= 3;
1147 color.setRgb( nums[0], nums[1], nums[2] );
1151 int pack = str.toInt( &res );
1153 color = Qtx::rgbSet( pack );
1158 color = QColor( str );
1159 res = color.isValid();
1166 \brief Convert bi-color value to the string representation.
1168 Bi-color value is specified as main color and integer delta
1169 value that is used to calculate secondary color by changing
1170 paremeters of the main color ("saturation" and "value"
1171 components in HSV notation).
1173 The resulting string consists of two sub-strings separated by
1174 '|' symbol. The first part represents main color
1175 (see colorToString() for more details), the second part is a
1178 Backward conversion can be done with stringToBiColor() method.
1180 \param color color to be converted
1181 \param delta delta value
1182 \return string representation of the bi-color value
1184 \sa stringToBiColor(), stringToColor()
1186 QString Qtx::biColorToString( const QColor& color, const int delta )
1188 return QString("%1|%2").arg( Qtx::colorToString( color ) ).arg( delta );
1192 \brief Restore bi-color value from the string representation.
1194 Bi-color value is specified as main color and integer delta
1195 value that is used to calculate secondary color by changing
1196 paremeters of the main color ("saturation" and "value"
1197 components in HSV notation).
1199 The parameter \a str should consist of two sub-strings separated
1200 by '|' symbol. The first part represents main color
1201 (see stringToColor() for more details), the second part is a
1204 Backward conversion can be done with biColorToString() method.
1206 \param str string representation of the bi-color value
1207 \param color resulting color value
1208 \param delta resulting delta value
1209 \return \c true if the conversion is successful and \c false otherwise
1211 \sa biColorToString(), stringToColor(), rgbSet()
1213 bool Qtx::stringToBiColor( const QString& str, QColor& color, int& delta )
1215 QStringList data = str.split( "|", QString::KeepEmptyParts );
1218 bool ok = data.count() > 0 && Qtx::stringToColor( data[0], c );
1220 if ( data.count() > 1 ) d = data[1].toInt( &dok );
1222 color = ok ? c : QColor();
1228 \brief Compute secondary color value from specified main color
1231 Secondary color is calculated by changing paremeters of the main
1232 color ("saturation" and "value" components in HSV notation) using
1235 If main color is invalid, result of the function is also invalid color.
1237 \param color source main color
1238 \param delta delta value
1239 \return resulting secondary color
1241 \sa biColorToString(), stringToBiColor()
1243 QColor Qtx::mainColorToSecondary( const QColor& color, int delta )
1246 if ( cs.isValid() ) {
1247 int val = qMin( 255, qMax( cs.value() + delta, 0 ) );
1248 int sat = qMin( 255, qMax( cs.saturation() + delta-(val-cs.value()), 0 ) );
1249 #ifdef BICOLOR_CHANGE_HUE
1250 const int BICOLOR_HUE_MAXDELTA = 40;
1251 int dh = delta-(val-cs.value())-(sat-cs.saturation());
1252 dh = qMin( BICOLOR_HUE_MAXDELTA, qAbs( dh ) ) * ( dh > 0 ? 1 : -1 );
1253 //int hue = qMin( 359, qMax( cs.hue() + delta-(val-cs.value())-(sat-cs.saturation()), 0 ) );
1254 //int hue = qMin( 359, qMax( cs.hue() + delta-(val-cs.value())-ds, 0 ) );
1255 int hue = cs.hue() + dh;
1256 if ( hue < 0 ) hue = 360 - hue;
1260 cs.setHsv( hue, sat, val );
1266 \brief Dump linear gradient to the string description.
1267 \param gradient linear gradient to be converted
1268 \return string representation of the linear gradient
1269 \sa stringToLinearGradient()
1271 QString Qtx::gradientToString( const QLinearGradient& gradient )
1275 data << QString::number( gradient.start().x() );
1276 data << QString::number( gradient.start().y() );
1277 data << QString::number( gradient.finalStop().x() );
1278 data << QString::number( gradient.finalStop().y() );
1279 switch( gradient.spread() )
1281 case QGradient::PadSpread:
1284 case QGradient::RepeatSpread:
1287 case QGradient::ReflectSpread:
1293 QGradientStops stops = gradient.stops();
1295 foreach ( stop, stops )
1297 data << QString::number( stop.first );
1298 data << colorToString( stop.second );
1300 return data.join( "|" );
1304 \brief Dump radial gradient to the string description.
1305 \param gradient radial gradient to be converted
1306 \return string representation of the radial gradient
1307 \sa stringToRadialGradient()
1309 QString Qtx::gradientToString( const QRadialGradient& gradient )
1313 data << QString::number( gradient.center().x() );
1314 data << QString::number( gradient.center().y() );
1315 data << QString::number( gradient.focalPoint().x() );
1316 data << QString::number( gradient.focalPoint().y() );
1317 data << QString::number( gradient.radius() );
1318 switch( gradient.spread() )
1320 case QGradient::PadSpread:
1323 case QGradient::RepeatSpread:
1326 case QGradient::ReflectSpread:
1332 QGradientStops stops = gradient.stops();
1334 foreach ( stop, stops )
1336 data << QString::number( stop.first );
1337 data << colorToString( stop.second );
1339 return data.join( "|" );
1343 \brief Dump conical gradient to the string description.
1344 \param gradient conical gradient to be converted
1345 \return string representation of the conical gradient
1346 \sa stringToConicalGradient()
1348 QString Qtx::gradientToString( const QConicalGradient& gradient )
1352 data << QString::number( gradient.center().x() );
1353 data << QString::number( gradient.center().y() );
1354 data << QString::number( gradient.angle() );
1355 switch( gradient.spread() )
1357 case QGradient::PadSpread:
1360 case QGradient::RepeatSpread:
1363 case QGradient::ReflectSpread:
1369 QGradientStops stops = gradient.stops();
1371 foreach ( stop, stops )
1373 data << QString::number( stop.first );
1374 data << colorToString( stop.second );
1376 return data.join( "|" );
1380 \brief Create linear gradient from its string representation.
1381 \param str string representation of the linear gradient
1382 \param gradient resulting linear gradient object
1383 \return \c true if the conversion is successful and \c false otherwise
1384 \sa gradientToString()
1386 bool Qtx::stringToLinearGradient( const QString& str, QLinearGradient& gradient )
1388 bool success = false;
1389 QStringList vals = str.split( "|", QString::SkipEmptyParts );
1390 if ( vals.count() > 4 && ( vals[0] == "linear" || vals[0] == "lg" ) )
1392 // start and end points
1393 double x1, y1, x2, y2;
1394 bool bOk1, bOk2, bOk3, bOk4;
1395 x1 = vals[1].toDouble( &bOk1 );
1396 y1 = vals[2].toDouble( &bOk2 );
1397 x2 = vals[3].toDouble( &bOk3 );
1398 y2 = vals[4].toDouble( &bOk4 );
1399 if ( bOk1 && bOk2 && bOk3 && bOk4 )
1401 gradient = QLinearGradient( x1, y1, x2, y2 );
1403 if ( vals.count() > 5 )
1405 QString spread = vals[ 5 ].trimmed().toLower();
1406 if ( spread == "pad" || spread == "0" )
1407 gradient.setSpread( QGradient::PadSpread );
1408 else if ( spread == "repeat" || spread == "2" )
1409 gradient.setSpread( QGradient::RepeatSpread );
1410 else if ( spread == "reflect" || spread == "1" )
1411 gradient.setSpread( QGradient::ReflectSpread );
1414 QGradientStops stops;
1415 for ( int i = 6; i < vals.count(); i+=2 )
1417 bool bOk5, bOk6 = false;
1419 double stop = vals[i].toDouble( &bOk5 );
1420 if ( i+1 < vals.count() )
1421 bOk6 = stringToColor( vals[ i+1 ], c );
1422 if ( bOk5 && stop >= 0.0 && stop <= 1.0 && bOk6 && c.isValid() )
1423 stops.append( QGradientStop( stop, c ) );
1425 gradient.setStops( stops );
1433 \brief Create radial gradient from its string representation.
1434 \param str string representation of the radial gradient
1435 \param gradient resulting radial gradient object
1436 \return \c true if the conversion is successful and \c false otherwise
1437 \sa gradientToString()
1439 bool Qtx::stringToRadialGradient( const QString& str, QRadialGradient& gradient )
1441 bool success = false;
1442 QStringList vals = str.split( "|", QString::SkipEmptyParts );
1443 if ( vals.count() > 5 && ( vals[0] == "radial" || vals[0] == "rg" ) )
1445 // center, radius and focal point
1446 double cx, cy, r, fx, fy;
1447 bool bOk1, bOk2, bOk3, bOk4, bOk5;
1448 cx = vals[1].toDouble( &bOk1 );
1449 cy = vals[2].toDouble( &bOk2 );
1450 fx = vals[3].toDouble( &bOk4 );
1451 fy = vals[4].toDouble( &bOk5 );
1452 r = vals[5].toDouble( &bOk3 );
1453 if ( bOk1 && bOk2 && bOk3 && bOk4 && bOk5 )
1455 gradient = QRadialGradient( cx, cy, r, fx, fy );
1457 if ( vals.count() > 6 )
1459 QString spread = vals[ 6 ].trimmed().toLower();
1460 if ( spread == "pad" || spread == "0" )
1461 gradient.setSpread( QGradient::PadSpread );
1462 else if ( spread == "repeat" || spread == "2" )
1463 gradient.setSpread( QGradient::RepeatSpread );
1464 else if ( spread == "reflect" || spread == "1" )
1465 gradient.setSpread( QGradient::ReflectSpread );
1468 QGradientStops stops;
1469 for ( int i = 7; i < vals.count(); i+=2 )
1471 bool bOk7, bOk8 = false;
1473 double stop = vals[i].toDouble( &bOk7 );
1474 if ( i+1 < vals.count() )
1475 bOk8 = stringToColor( vals[ i+1 ], c );
1476 if ( bOk7 && stop >= 0.0 && stop <= 1.0 && bOk8 && c.isValid() )
1477 stops.append( QGradientStop( stop, c ) );
1479 gradient.setStops( stops );
1487 \brief Create conical gradient from its string representation.
1488 \param str string representation of the conical gradient
1489 \param gradient resulting conical gradient object
1490 \return \c true if the conversion is successful and \c false otherwise
1491 \sa gradientToString()
1493 bool Qtx::stringToConicalGradient( const QString& str, QConicalGradient& gradient )
1495 bool success = false;
1496 QStringList vals = str.split( "|", QString::SkipEmptyParts );
1497 if ( vals.count() > 3 && ( vals[0] == "conical" || vals[0] == "cg" ) )
1501 bool bOk1, bOk2, bOk3;
1502 cx = vals[1].toDouble( &bOk1 );
1503 cy = vals[2].toDouble( &bOk2 );
1504 a = vals[3].toDouble( &bOk3 );
1505 if ( bOk1 && bOk2 && bOk3 )
1507 gradient = QConicalGradient( cx, cy, a );
1509 if ( vals.count() > 4 )
1511 QString spread = vals[ 4 ].trimmed().toLower();
1512 if ( spread == "pad" || spread == "0" )
1513 gradient.setSpread( QGradient::PadSpread );
1514 else if ( spread == "repeat" || spread == "2" )
1515 gradient.setSpread( QGradient::RepeatSpread );
1516 else if ( spread == "reflect" || spread == "1" )
1517 gradient.setSpread( QGradient::ReflectSpread );
1520 QGradientStops stops;
1521 for ( int i = 5; i < vals.count(); i+=2 )
1523 bool bOk4, bOk5 = false;
1525 double stop = vals[i].toDouble( &bOk4 );
1526 if ( i+1 < vals.count() )
1527 bOk5 = stringToColor( vals[ i+1 ], c );
1528 if ( bOk4 && stop >= 0.0 && stop <= 1.0 && bOk5 && c.isValid() )
1529 stops.append( QGradientStop( stop, c ) );
1531 gradient.setStops( stops );
1539 \brief Convert background data to the string representation.
1540 The resulting string consists of several sub-strings separated by ';' symbol.
1541 These sub-strings represent:
1542 1. background type (enumerator, see Qtx::BackgroundMode)
1543 2. texture image file name (string)
1544 3. texture mode (enumerator, see Qtx::TextureMode)
1545 4. "show texture" flag (boolean)
1546 5. first color (for simple gradient data) or solid color (for single-colored mode)
1547 6. second color (for simple gradient data)
1548 7. type of simple gradient (some integer identifier)
1549 8. complex gradient data (for custom gradient mode)
1550 Each sub-string consists of keyword/value couple, in form of "<keyword>=<value>".
1552 Backward conversion can be done with stringToBackground() method.
1554 \param bgData background data
1555 \return string representation of the background data
1557 \sa stringToBackground()
1559 QString Qtx::backgroundToString( const Qtx::BackgroundData& bgData )
1561 const QString dtSep = ";";
1562 const QString kwSep = "=";
1563 const QString kwBgType = "bt";
1564 const QString kwFileName = "fn";
1565 const QString kwTextureMode = "tm";
1566 const QString kwShowTexture = "ts";
1567 const QString kwFirstColor = "c1";
1568 const QString kwSecondColor = "c2";
1569 const QString kwGrType = "gt";
1570 const QString kwGrData = "gr";
1572 Qtx::BackgroundMode bgMode = bgData.mode();
1574 Qtx::TextureMode textureMode = bgData.texture( fileName );
1575 bool showTexture = bgData.isTextureShown();
1577 int gradientType = bgData.gradient( c1, c2 );
1578 const QGradient* gradient = bgData.gradient();
1581 switch ( gradient->type() ) {
1582 case QGradient::LinearGradient:
1583 grString = gradientToString( *(static_cast<const QLinearGradient*>( gradient )) );
1585 case QGradient::RadialGradient:
1586 grString = gradientToString( *(static_cast<const QRadialGradient*>( gradient )) );
1588 case QGradient::ConicalGradient:
1589 grString = gradientToString( *(static_cast<const QConicalGradient*>( gradient )) );
1596 data << QString( "%1%2%3" ).arg( kwBgType ).arg( kwSep ).arg( (int)bgMode );
1597 data << QString( "%1%2%3" ).arg( kwFileName ).arg( kwSep ).arg( fileName );
1598 data << QString( "%1%2%3" ).arg( kwTextureMode ).arg( kwSep ).arg( (int)textureMode );
1599 data << QString( "%1%2%3" ).arg( kwShowTexture ).arg( kwSep ).arg( showTexture ? "true" : "false" );
1600 data << QString( "%1%2%3" ).arg( kwFirstColor ).arg( kwSep ).arg( Qtx::colorToString( c1 ) );
1601 data << QString( "%1%2%3" ).arg( kwSecondColor ).arg( kwSep ).arg( Qtx::colorToString( c2 ) );
1602 data << QString( "%1%2%3" ).arg( kwGrType ).arg( kwSep ).arg( gradientType );
1603 data << QString( "%1%2%3" ).arg( kwGrData ).arg( kwSep ).arg( grString );
1605 return data.join( dtSep );
1609 \brief Restore background data from the string representation.
1611 The string should consist of several sub-strings separated by ';' symbol.
1612 Each sub-string consists of keyword/value couple, in form of "<keyword>=<value>".
1613 The sub-strings can follow in arbitrary order, some keywords can be missing.
1614 The background data is described by the following values:
1615 - background type (enumerator, see Qtx::BackgroundMode), keyword "bt"
1616 - texture image file name (string), keyword "fn"
1617 - texture mode (enumerator, see Qtx::TextureMode), keyword "tm"
1618 - "show texture" flag (boolean), keyword "ts"
1619 - first color (for simple gradient data) or solid color (for single-colored mode), keyword "c1"
1620 - second color (for simple gradient data), keyword "c2"
1621 - name of gradient type (string), keyword "gt"
1622 - complex gradient data (for custom gradient mode), keyword "gr"
1624 Also, for backward compatibility, background data can be represented by
1625 single color value, see stringToColor().
1627 Backward conversion can be done with backgroundToString() method.
1628 Returns invalid background if conversion could not be done.
1631 Qtx::BackgroundData bgData = Qtx::stringToBackground( str );
1632 if ( bgData.isValid() ) ) doSomething( bgData );
1635 \param theString string representation of the background data
1636 \return resulting background data (invalid if conversion has failed)
1638 \sa backgroundToString()
1641 Qtx::BackgroundData Qtx::stringToBackground( const QString& str )
1643 const QString dtSep = ";";
1644 const QString kwSep = "=";
1645 const QString kwBgType = "bt";
1646 const QString kwFileName = "fn";
1647 const QString kwTextureMode = "tm";
1648 const QString kwShowTexture = "ts";
1649 const QString kwFirstColor = "c1";
1650 const QString kwSecondColor = "c2";
1651 const QString kwGrType = "gt";
1652 const QString kwGrData = "gr";
1654 Qtx::BackgroundData bgData = BackgroundData();
1656 QStringList data = str.split( dtSep, QString::KeepEmptyParts );
1659 if ( data.count() == 1 && !data.contains( kwSep ) && stringToColor( data[0], c ) ) {
1660 // solid color mode, for backward compatibility
1661 bgData.setColor( c );
1664 QMap<QString, QString> dmap;
1666 foreach( QString d, data ) {
1667 QStringList items = d.split( kwSep, QString::KeepEmptyParts );
1668 if ( items.count() > 0 ) {
1669 QString kw = items.takeFirst().trimmed().toLower(); // keyword
1670 QString val = items.join( kwSep ).trimmed(); // if value contains "=" symbol, we have to restore it
1674 QString bgMode = dmap.value( kwBgType, QString() );
1675 QString fileName = dmap.value( kwFileName, QString() );
1676 QString textureMode = dmap.value( kwTextureMode, QString() );
1677 QString showTexture = dmap.value( kwShowTexture, QString() );
1678 QString color1 = dmap.value( kwFirstColor, QString() );
1679 QString color2 = dmap.value( kwSecondColor, QString() );
1680 QString gradientType = dmap.value( kwGrType, QString() );
1681 QString gradient = dmap.value( kwGrData, QString() );
1684 if ( !fileName.isEmpty() || !textureMode.isEmpty() || !showTexture.isEmpty() ) {
1685 Qtx::TextureMode m = (Qtx::TextureMode)( stringToInt( textureMode, Qtx::CenterTexture,
1686 Qtx::CenterTexture, Qtx::StretchTexture ) );
1687 bgData.setTexture( fileName, m );
1688 QStringList boolvars; boolvars << "true" << "yes" << "ok" << "1";
1689 if ( boolvars.contains( showTexture.trimmed().toLower() ) )
1690 bgData.setTextureShown( true );
1694 bool ok = Qtx::stringToColor( color1, c1 );
1696 bgData.setColor( c1 );
1698 // try simple gradient mode
1699 ok = Qtx::stringToColor( color2, c2 );
1700 if ( ok || !gradientType.isEmpty() ) {
1701 int gt = gradientType.toInt( &ok );
1702 bgData.setGradient( ok ? gt : -1, c1, c2 );
1704 // try custom gradient mode
1706 QConicalGradient cg;
1708 ok = Qtx::stringToLinearGradient( gradient, lg );
1710 bgData.setGradient( lg );
1712 ok = Qtx::stringToRadialGradient( gradient, rg );
1714 bgData.setGradient( rg );
1716 ok = Qtx::stringToConicalGradient( gradient, cg );
1718 bgData.setGradient( cg );
1721 // finally set background mode
1722 Qtx::BackgroundMode m = (Qtx::BackgroundMode)( stringToInt( bgMode, Qtx::ColorBackground,
1723 Qtx::NoBackground, Qtx::CustomGradientBackground ) );
1724 bgData.setMode( m );
1731 \class Qtx::Localizer
1732 \brief Localization helper
1734 This helper class can be used to solve the localization problems,
1735 usually related to the textual files reading/writing, namely when
1736 floating point values are read / written with API functions.
1737 The problem relates to such locale specific settings as decimal point
1738 separator, thousands separator, etc.
1740 To use the Localizer class, just create a local variable in the beginning
1741 of the code where you need to read / write data from textual file(s).
1742 The constructor of the class forces setting "C" locale temporarily.
1743 The destructor switches back to the initial locale.
1745 There are two ways to create a localizer.
1746 First constructor accepts category and locale value to be forced as parameters.
1747 The second constructor does not take parameters, and is just a shortcut to the
1748 first one, setting LC_NUMERIC as a category and "C" as a locale to force.
1758 \brief Default constructor. Forces "C" locale to be set as LC_NUMERIC.
1760 Qtx::Localizer::Localizer()
1762 init( LC_NUMERIC, "C" );
1766 \brief Constructor. Forces \a locale to be set for \a category.
1768 Qtx::Localizer::Localizer( int category, const char* locale )
1770 init( category, locale );
1774 \brief Internal initialization
1777 void Qtx::Localizer::init( int category, const char* locale )
1779 myCategory = category;
1780 myOriginalLocale = setlocale( category, NULL );
1781 setlocale( category, locale );
1785 \brief Destructor. Reverts back to the initial locale.
1787 Qtx::Localizer::~Localizer()
1789 setlocale( myCategory, myOriginalLocale.toLatin1().constData() );
1793 \class Qtx::BackgroundData
1794 \brief Stores background data
1796 This class is used to store background data. Depending on the mode,
1797 the background can be specified by:
1798 - image (by assigning the file name to be used as background texture), see setTexture(), setTextureShown()
1799 - single color (by assigning any color), see setColor()
1800 - simple two-color gradient (with the gradient type id and two colors), see setGradient( int, const QColor&, const QColor& )
1801 - complex gradient (by assigning arbitrary gradient data), see setGradient( const QGradient& )
1803 The class stores all the data passed to it, so switching between different modes can be done
1804 just by calling setMode() function.
1806 \note Texture is used with combination of the background mode.
1808 \note Two-color gradient is specified by two colors and integer identifier. The interpretation of
1809 this identifier should be done in the calling code.
1812 Qtx::BackgroundData bg;
1813 bg.setColor( QColor(100, 100, 100) ); // bg is switched to Qtx::ColorBackground mode
1814 bg.setGradient( Qt::Horizontal, Qt::gray, Qt::white ); // bg is switched to Qtx::ColorBackground mode
1815 QLinearGradient grad( 0,0,1,1 );
1816 grad.setColorAt( 0.0, Qt::gray );
1817 grad.setColorAt( 0.5, Qt::white );
1818 grad.setColorAt( 1.0, Qt::green );
1819 grad.setSpread( QGradient::PadSpread );
1820 bg.setGradient( grad ); // bg is switched to Qtx::CustomGradientBackground mode
1821 bg.setMode( Qtx::ColorBackground ); // bg is switched back to Qtx::ColorBackground mode
1822 bg.setTexture( "/data/images/background.png" ); // specify texture (in the centered mode by default)
1823 bg.setTextureShown( true ); // draw texture on the solid color background
1828 \brief Default constructor.
1829 Creates invalid background data.
1831 Qtx::BackgroundData::BackgroundData()
1832 : myTextureMode( Qtx::CenterTexture ), myGradientType( -1 ), myTextureShown( false )
1834 setMode( Qtx::NoBackground );
1839 Creates background data initialized with the specified color
1842 Qtx::BackgroundData::BackgroundData( const QColor& c )
1843 : myTextureMode( Qtx::CenterTexture ), myGradientType( -1 ), myTextureShown( false )
1850 Creates background data initialized with the specified two-color gradient
1851 \param type gradient type identifier
1852 \param c1 first gradient color
1853 \param c2 second gradient color
1854 \note the interpretation of the gradient identifier should be done in the calling code
1856 Qtx::BackgroundData::BackgroundData( int type, const QColor& c1, const QColor& c2 )
1857 : myTextureMode( Qtx::CenterTexture ), myGradientType( -1 ), myTextureShown( false )
1859 setGradient( type, c1, c2 );
1864 Creates background data initialized with the arbirtary gradient data
1865 \param grad gradient data
1867 Qtx::BackgroundData::BackgroundData( const QGradient& grad )
1868 : myTextureMode( Qtx::CenterTexture ), myGradientType( -1 ), myTextureShown( false )
1870 setGradient( grad );
1876 Qtx::BackgroundData::~BackgroundData()
1881 \brief Compares two background data objects
1883 bool Qtx::BackgroundData::operator==( const Qtx::BackgroundData& other ) const
1886 ( myMode == other.myMode ) &&
1887 ( myTextureMode == other.myTextureMode ) &&
1888 ( myFileName == other.myFileName ) &&
1889 ( myColors == other.myColors ) &&
1890 ( myGradientType == other.myGradientType ) &&
1891 ( myGradient == other.myGradient ) &&
1892 ( myTextureShown == other.myTextureShown );
1896 \brief Returns \c false if background data is not set (invalid)
1897 \return \c true if background data is valid or \c false otherwise
1900 bool Qtx::BackgroundData::isValid() const
1902 return myMode != Qtx::NoBackground;
1906 \brief Get background mode
1907 \return current background mode
1910 Qtx::BackgroundMode Qtx::BackgroundData::mode() const
1916 \brief Set background mode
1917 \param m background mode being set
1920 void Qtx::BackgroundData::setMode( const Qtx::BackgroundMode m )
1926 \brief Get file name used as a texture image
1927 \return path to the texture image file
1928 \sa setTexture(), setTextureShown()
1930 Qtx::TextureMode Qtx::BackgroundData::texture( QString& fileName ) const
1932 fileName = myFileName;
1933 return myTextureMode;
1937 \brief Set file name to be used as a texture image.
1939 \note To show texture image on the background it is necessary to call additionally
1940 setTextureShown() method.
1942 \param fileName path to the texture image file name
1943 \param m texture mode (Qtx::CenterTexture by default)
1944 \sa texture(), setTextureShown()
1946 void Qtx::BackgroundData::setTexture( const QString& fileName, const Qtx::TextureMode m )
1948 myFileName = fileName;
1953 \brief Check if "show texture" flag is switched on
1954 \return \c true if "show texture" flag is set or \c false otherwise
1955 \sa setTextureShown(), texture()
1957 bool Qtx::BackgroundData::isTextureShown() const
1959 return myTextureShown;
1963 \brief Specify if texture should be shown on the background or no.
1964 \param on \c true if texture should be shown or \c false otherwise
1965 \sa isTextureShown(), texture()
1967 void Qtx::BackgroundData::setTextureShown( bool on )
1969 myTextureShown = on;
1973 \brief Get background color. Returns null QColor if color is not set
1974 \return solid background color
1975 \sa setColor(), mode()
1977 QColor Qtx::BackgroundData::color() const
1979 return myColors.count() > 0 ? myColors[0] : QColor();
1983 \brief Set background color and switch to the Qtx::ColorBackground mode
1987 void Qtx::BackgroundData::setColor( const QColor& c )
1991 setMode( Qtx::ColorBackground );
1995 \brief Get simple gradient data.
1996 Returns -1 and null QColor for \a c1 and \a c2 if gradient data is not set
1997 \param c1 first gradient color is returned via this parameter
1998 \param c2 second gradient color is returned via this parameter
1999 \return current two-colored gradient mode type identifier
2000 \note the interpretation of the gradient identifier should be done in the calling code
2001 \sa setGradient(int, const QColor&, const QColor&), mode()
2003 int Qtx::BackgroundData::gradient( QColor& c1, QColor& c2 ) const
2005 c1 = myColors.count() > 0 ? myColors[0] : QColor();
2006 c2 = myColors.count() > 1 ? myColors[1] : ( myColors.count() > 0 ? myColors[0] : QColor() );
2007 return myGradientType;
2011 \brief Set simple background gradient data and switch to the Qtx::SimpleGradientBackground mode
2012 \param type two-colored gradient mode type identifier
2013 \param c1 first gradient color is returned via this parameter
2014 \param c2 second gradient color is returned via this parameter
2015 \note the interpretation of the gradient identifier should be done in the calling code
2016 \sa gradient(QColor&, QColor&), mode()
2018 void Qtx::BackgroundData::setGradient( int type, const QColor& c1, const QColor& c2 )
2021 myColors << c1 << c2;
2022 myGradientType = type;
2023 setMode( Qtx::SimpleGradientBackground );
2027 \brief Get complex gradient data.
2028 Returns QGradient of QGradient::NoGradient if gradient data is not set
2029 \note This function does not transform simple gradient data set with
2030 setGradient( const QString&, const QColor&, const QColor& ) to QGradient class
2031 \return gradient data
2032 \sa setGradient(const QGradient&), mode()
2034 const QGradient* Qtx::BackgroundData::gradient() const
2040 \brief Set complex background gradient data and switch to the Qtx::CustomGradientBackground mode
2041 \param grad gradient data (QLinearGradient, QRadialGradient or QConicalGradient)
2042 \sa gradient(), mode()
2044 void Qtx::BackgroundData::setGradient( const QGradient& grad )
2047 setMode( Qtx::CustomGradientBackground );
2051 \brief Convert string representation of version identifier to the numerical value.
2052 Resulting value can be used for comparison of different versions (lower, higher, equal).
2054 String representation of the version consists of zero or more components:
2056 [major[.minor[.release[patchid]]]]
2059 - major is version major number
2060 - minor is version minor number
2061 - release is version release number
2062 - patchid is a version dev identifier which is one of the following
2063 * 1 letter optionally followed by 1 or 2 digits, e.g. "a" for "alpha", "b1" for "beta 1"
2064 * "rc" optionally followed by 1 or 2 digits, e.g. "rc1" for "release candidate 1"
2065 * "dev" for development version (note: 7.4.0dev > 7.4.0, 7.4.0dev < 7.4.1, 7.4.0dev < 7.4.0a1)
2067 If version string does not include any component or has invalid format, the function returns 0.
2071 1.2.3a - version 1.2.3 alpha
2072 3.3.3b1 - version 3.3.3 beta 1
2073 7.4.0rc1 - version 7.4.0 release candidate 1
2074 7.4.0dev - dev version, i.e. future version 7.4.1 (or 7.5.0)
2076 \param version string representation of version
2077 \return numerical identifier of the version
2079 long Qtx::versionToId( const QString& version )
2083 QRegExp vers_exp( "^([0-9]+)([A-Z]|RC|DEV)?([0-9]{0,2})$", Qt::CaseInsensitive );
2085 QStringList vers = version.split( ".", QString::SkipEmptyParts );
2086 int major=0, minor=0;
2087 int release = 0, dev1 = 0, dev2 = 0;
2088 if ( vers.count() > 0 ) major = vers[0].toInt();
2089 if ( vers.count() > 1 ) minor = vers[1].toInt();
2090 if ( vers.count() > 2 ) {
2091 if ( vers_exp.indexIn( vers[2] ) != -1 ) {
2092 release = vers_exp.cap( 1 ).toInt();
2093 QString tag = vers_exp.cap( 2 ).toLower();
2094 if ( !tag.isEmpty() ) {
2095 // patchid is subtracted from version number
2096 // a = 55 --> -(55 * 100) + patch number --> 4500..4599, e.g. 7.4.1a1 -> 704004501
2097 // b = 54 --> -(54 * 100) + patch number --> 4600..4699, e.g. 7.4.1b1 -> 704004601
2098 // c = 53 --> -(53 * 100) + patch number --> 4700..4799, e.g. 7.4.1c1 -> 704004701
2100 // z = 30 --> -( 1 * 100) + patch number --> 7000..7099, e.g. 7.4.1z1 -> 704007001
2101 // rc = 1 --> -( 1 * 100) + patch number --> 9900..9999, e.g. 7.4.1rc1 -> 704009901
2102 // dev = -1 --> +( 1 * 100) + patch number --> 0100..0199, e.g. 7.4.1dev -> 704010100
2104 // i.e. "a" < "b" < ... < "z" < "rc" < [stable] < "dev"
2107 else if ( tag == "dev" )
2110 dev1 = (int)( QChar('z').toLatin1() ) - (int)( tag[ 0 ].toLatin1() ) + 30;
2112 if ( !vers_exp.cap( 3 ).isEmpty() )
2113 dev2 = vers_exp.cap( 3 ).toInt();
2117 int dev = dev1*100-dev2;
2120 id*=100; id+=release;
2128 \brief Get Qt installation directory
2130 The function tries to detect qt installation directory by analyzing the system variables in the following order:
2135 Optional parameter \a context allows obtaining subdirectory in the Qt installation directory.
2137 \param context optional sub-directory
2138 \return path to the Qt installation directory (or its sub-folder, if \a context is specified)
2141 QString Qtx::qtDir( const QString& context )
2144 QStringList vars = { "QT5_ROOT_DIR", "QT_ROOT_DIR", "QTDIR" };
2146 for (int i = 0; i < vars.length() && qtPath.isEmpty(); i++ ) {
2147 qtPath = getenv(vars[i]);
2149 if ( !qtPath.isEmpty() && !context.isEmpty() )
2150 qtPath = QDir( qtPath ).absoluteFilePath( context );
2155 Creates font from string description
2157 QFont Qtx::stringToFont( const QString& fontDescription )
2160 if ( fontDescription.trimmed().isEmpty() || !font.fromString( fontDescription ) )
2161 font = QFont( "Courier", 11 );
2165 QString Qtx::getenv(const QString & envVar)
2169 value = qgetenv(envVar.toLocal8Bit().constData());
2171 LPTSTR buff = new TCHAR[MAX_VALUE_SIZE];
2173 LPTSTR anEnvVar = new TCHAR[envVar.length() + 1];
2174 anEnvVar[envVar.toWCharArray(anEnvVar)] = '\0';
2176 const TCHAR* anEnvVar = envVar.toLocal8Bit(buff).constData();
2178 const DWORD ret = GetEnvironmentVariable(anEnvVar, buff, MAX_VALUE_SIZE);
2182 value = QString::fromWCharArray(buff);
2184 value = QString::fromLocal8Bit(buff);
2195 #if !defined WIN32 && !defined __APPLE__
2197 #include <X11/Xlib.h>
2201 \brief Open the default X display and returns pointer to it.
2202 This method is available on Linux only.
2203 \return Pointer to X display.
2206 void* Qtx::getDisplay()
2208 static Display* pDisplay = NULL;
2210 pDisplay = XOpenDisplay( NULL );
2215 \brief Returns pointer to X visual suitable for 3D rendering.
2216 This method is available on Linux only.
2217 \return Pointer to X visual.
2220 Qt::HANDLE Qtx::getVisual()
2222 Qt::HANDLE res = (Qt::HANDLE)NULL;
2224 Display* pDisplay = (Display*)getDisplay();
2231 // Make sure OpenGL's GLX extension supported
2232 if( !glXQueryExtension( pDisplay, &errorBase, &eventBase ) ){
2233 qCritical( "Could not find glx extension" );
2237 // Find an appropriate visual
2239 int doubleBufferVisual[] = {
2240 GLX_RENDER_TYPE, GLX_RGBA_BIT, // Needs to support OpenGL
2245 GLX_DEPTH_SIZE, 16, // Needs to support a 16 bit depth buffer
2246 GLX_DOUBLEBUFFER, 1, // Needs to support double-buffering
2247 GLX_STEREO, 1, // Needs to support stereo rendering
2248 GLX_STENCIL_SIZE, 1,
2249 0x20B2, 1, // Needs to support srgb profile
2253 // Try for the double-bufferd visual first
2254 XVisualInfo *visualInfo = NULL;
2255 visualInfo = glXChooseVisual( pDisplay, DefaultScreen(pDisplay), doubleBufferVisual );
2257 if( visualInfo == NULL ){
2258 qCritical( "Could not find matching glx visual" );
2262 qDebug() << "Picked visual 0x" << hex << XVisualIDFromVisual( visualInfo->visual );
2263 res = (Qt::HANDLE)( visualInfo->visual );
2271 \brief Set default QSurfaceFormat for an application.
2273 This application property should be set before a creation of the QApplication.
2275 void Qtx::initDefaultSurfaceFormat()
2277 // Settings from Paraview:
2278 // This piece of code was taken from QVTKOpenGLWidget::defaultFormat() method in
2279 // order to avoid dependency of the SALOME_Session_Server on vtk libraries
2281 fmt.setRenderableType(QSurfaceFormat::OpenGL);
2282 fmt.setVersion(3, 2);
2283 fmt.setProfile(QSurfaceFormat::CoreProfile);
2284 fmt.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
2285 fmt.setRedBufferSize(1);
2286 fmt.setGreenBufferSize(1);
2287 fmt.setBlueBufferSize(1);
2288 fmt.setDepthBufferSize(1);
2289 fmt.setStencilBufferSize(0);
2291 fmt.setAlphaBufferSize(0);
2293 fmt.setAlphaBufferSize(0);
2295 fmt.setStereo(false);
2298 // Settings for OCCT viewer window:
2299 fmt.setDepthBufferSize(16);
2300 fmt.setStencilBufferSize(1);
2301 // fmt.setProfile(QSurfaceFormat::CompatibilityProfile);
2303 QSurfaceFormat::setDefaultFormat(fmt);
2307 \class Qtx::CmdLineArgs
2308 \brief Get access to the command line arguments in the C-like manner.
2310 This class translates command line arguments stored in QApplication in form of QStrlingList
2311 to the char* array, in the same way as they specified to main() function.
2313 Constructor of class allocates required memory to store arguments; destructor deallocates it,
2314 This allows using this class as a local variable:
2317 Qtx::CmdLineArgs args;
2318 some_function(args.argc(), args.argv()); // function that has main()-like syntax.
2323 \brief Default constructor.
2325 Qtx::CmdLineArgs::CmdLineArgs()
2327 QStringList args = QCoreApplication::arguments();
2328 myArgc = args.size();
2329 myArgv = new char*[myArgc];
2330 for ( int i = 0; i < myArgc; i++ ) {
2331 QByteArray ba = args[i].toUtf8();
2332 myArgv[i] = qstrdup(ba.constData());
2337 \brief Destructor. Deallocates the array with command line arguments
2339 Qtx::CmdLineArgs::~CmdLineArgs()
2341 for ( int i = 0; i < myArgc; i++ )
2347 \brief Get number of command line arguments
2348 \return number of arguments
2350 int Qtx::CmdLineArgs::argc() const
2356 \brief Get command line arguments
2357 \return command line arguments
2359 char** Qtx::CmdLineArgs::argv() const