2018-07-08 11:46:23 -04:00
# include " FractoriumPch.h "
2014-07-08 03:11:14 -04:00
# include "Fractorium.h"
2015-10-27 00:31:35 -04:00
# include "QssDialog.h"
2014-07-08 03:11:14 -04:00
2015-05-30 00:08:44 -04:00
// X11 headers on Linux define this, causing build errors.
# ifdef KeyRelease
# undef KeyRelease
# endif
2014-07-08 03:11:14 -04:00
/// <summary>
/// Constructor that initializes the entire program.
/// The setup process is very lengthy because it requires many custom modifications
/// to the GUI widgets that are not possible to do through the designer. So if something
/// is present here, it's safe to assume it can't be done in the designer.
/// </summary>
2014-12-11 00:50:15 -05:00
/// <param name="p">The parent widget of this item</param>
2015-12-31 16:41:59 -05:00
Fractorium : : Fractorium ( QWidget * p )
: QMainWindow ( p )
2014-07-08 03:11:14 -04:00
{
2016-03-01 20:26:45 -05:00
int iconSize_ = 9 ;
2014-07-26 15:03:51 -04:00
size_t i = 0 ;
2015-10-27 00:31:35 -04:00
string s ;
2014-07-08 03:11:14 -04:00
Timing t ;
ui . setupUi ( this ) ;
2015-12-31 16:41:59 -05:00
m_Info = OpenCLInfo : : Instance ( ) ;
2017-05-31 22:50:05 -04:00
qRegisterMetaType < size_t > ( " size_t " ) ;
2014-07-08 03:11:14 -04:00
qRegisterMetaType < QVector < int > > ( " QVector<int> " ) ; //For previews.
2014-12-06 00:05:09 -05:00
qRegisterMetaType < vector < byte > > ( " vector<byte> " ) ;
2017-07-22 16:43:35 -04:00
qRegisterMetaType < vv4F > ( " vv4F " ) ;
2014-07-08 03:11:14 -04:00
qRegisterMetaType < EmberTreeWidgetItemBase * > ( " EmberTreeWidgetItemBase* " ) ;
2015-06-17 23:05:53 -04:00
tabifyDockWidget ( ui . LibraryDockWidget , ui . FlameDockWidget ) ;
tabifyDockWidget ( ui . FlameDockWidget , ui . XformsDockWidget ) ;
tabifyDockWidget ( ui . XformsDockWidget , ui . XaosDockWidget ) ;
tabifyDockWidget ( ui . XaosDockWidget , ui . PaletteDockWidget ) ;
tabifyDockWidget ( ui . PaletteDockWidget , ui . InfoDockWidget ) ;
2017-12-16 00:05:58 -05:00
setTabPosition ( Qt : : LeftDockWidgetArea | Qt : : RightDockWidgetArea , QTabWidget : : TabPosition : : North ) ;
setTabShape ( QTabWidget : : TabShape : : Triangular ) ;
2015-06-20 14:35:08 -04:00
m_Docks . reserve ( 8 ) ;
m_Docks . push_back ( ui . LibraryDockWidget ) ;
m_Docks . push_back ( ui . FlameDockWidget ) ;
m_Docks . push_back ( ui . XformsDockWidget ) ;
m_Docks . push_back ( ui . XaosDockWidget ) ;
m_Docks . push_back ( ui . PaletteDockWidget ) ;
m_Docks . push_back ( ui . InfoDockWidget ) ;
2017-12-16 00:05:58 -05:00
for ( auto dock : m_Docks ) //Prevents a dock from ever getting accidentally hidden.
{
dock - > setWindowFlags ( dock - > windowFlags ( ) & Qt : : WindowStaysOnTopHint ) ;
2017-12-22 01:11:18 -05:00
dock - > setAllowedAreas ( Qt : : DockWidgetArea : : LeftDockWidgetArea
//#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
| Qt : : DockWidgetArea : : RightDockWidgetArea
//#endif
) ;
2017-12-16 00:05:58 -05:00
}
2014-07-08 03:11:14 -04:00
m_FontSize = 9 ;
m_VarSortMode = 1 ; //Sort by weight by default.
2015-05-31 01:14:34 -04:00
m_PaletteSortMode = 0 ; //Sort by palette ascending by default.
2014-07-08 03:11:14 -04:00
m_ColorDialog = new QColorDialog ( this ) ;
2016-12-05 22:04:33 -05:00
m_Settings = FractoriumSettings : : Instance ( ) ;
2015-10-27 00:31:35 -04:00
m_QssDialog = new QssDialog ( this ) ;
2016-12-05 22:04:33 -05:00
m_FinalRenderDialog = new FractoriumFinalRenderDialog ( this ) ;
m_OptionsDialog = new FractoriumOptionsDialog ( this ) ;
m_VarDialog = new FractoriumVariationsDialog ( this ) ;
2014-07-08 03:11:14 -04:00
m_AboutDialog = new FractoriumAboutDialog ( this ) ;
2014-09-08 00:05:27 -04:00
//Put the about dialog in the screen center.
const QRect screen = QApplication : : desktop ( ) - > screenGeometry ( ) ;
m_AboutDialog - > move ( screen . center ( ) - m_AboutDialog - > rect ( ) . center ( ) ) ;
2014-07-08 03:11:14 -04:00
connect ( m_ColorDialog , SIGNAL ( colorSelected ( const QColor & ) ) , this , SLOT ( OnColorSelected ( const QColor & ) ) , Qt : : QueuedConnection ) ;
2014-07-26 15:03:51 -04:00
m_XformComboColors [ i + + ] = QColor ( 0XFF , 0X00 , 0X00 ) ;
m_XformComboColors [ i + + ] = QColor ( 0XCC , 0XCC , 0X00 ) ;
m_XformComboColors [ i + + ] = QColor ( 0X00 , 0XCC , 0X00 ) ;
m_XformComboColors [ i + + ] = QColor ( 0X00 , 0XCC , 0XCC ) ;
m_XformComboColors [ i + + ] = QColor ( 0X40 , 0X40 , 0XFF ) ;
m_XformComboColors [ i + + ] = QColor ( 0XCC , 0X00 , 0XCC ) ;
m_XformComboColors [ i + + ] = QColor ( 0XCC , 0X80 , 0X00 ) ;
m_XformComboColors [ i + + ] = QColor ( 0X80 , 0X00 , 0X4F ) ;
m_XformComboColors [ i + + ] = QColor ( 0X80 , 0X80 , 0X22 ) ;
m_XformComboColors [ i + + ] = QColor ( 0X60 , 0X80 , 0X60 ) ;
m_XformComboColors [ i + + ] = QColor ( 0X50 , 0X80 , 0X80 ) ;
m_XformComboColors [ i + + ] = QColor ( 0X4F , 0X4F , 0X80 ) ;
m_XformComboColors [ i + + ] = QColor ( 0X80 , 0X50 , 0X80 ) ;
m_XformComboColors [ i + + ] = QColor ( 0X80 , 0X60 , 0X22 ) ;
m_FinalXformComboColor = QColor ( 0x7F , 0x7F , 0x7F ) ;
2015-12-31 16:41:59 -05:00
2014-07-26 15:03:51 -04:00
for ( i = 0 ; i < XFORM_COLOR_COUNT ; i + + )
{
2014-12-11 00:50:15 -05:00
QPixmap pixmap ( iconSize_ , iconSize_ ) ;
2014-07-26 15:03:51 -04:00
pixmap . fill ( m_XformComboColors [ i ] ) ;
m_XformComboIcons [ i ] = QIcon ( pixmap ) ;
}
2014-12-11 00:50:15 -05:00
QPixmap pixmap ( iconSize_ , iconSize_ ) ;
2014-07-26 15:03:51 -04:00
pixmap . fill ( m_FinalXformComboColor ) ;
m_FinalXformComboIcon = QIcon ( pixmap ) ;
2014-07-08 03:11:14 -04:00
InitToolbarUI ( ) ;
InitParamsUI ( ) ;
InitXformsUI ( ) ;
InitXformsColorUI ( ) ;
InitXformsAffineUI ( ) ;
InitXformsVariationsUI ( ) ;
2015-04-27 01:11:56 -04:00
InitXformsSelectUI ( ) ;
InitXaosUI ( ) ;
2014-07-08 03:11:14 -04:00
InitPaletteUI ( ) ;
InitLibraryUI ( ) ;
2015-07-15 23:27:32 -04:00
InitInfoUI ( ) ;
2014-07-08 03:11:14 -04:00
InitMenusUI ( ) ;
//This will init the controller and fill in the variations and palette tables with template specific instances
//of their respective objects.
# ifdef DO_DOUBLE
2015-12-31 16:41:59 -05:00
2014-07-08 03:11:14 -04:00
if ( m_Settings - > Double ( ) )
2014-10-18 17:07:07 -04:00
m_Controller = unique_ptr < FractoriumEmberControllerBase > ( new FractoriumEmberController < double > ( this ) ) ;
2014-07-08 03:11:14 -04:00
else
# endif
2014-10-18 17:07:07 -04:00
m_Controller = unique_ptr < FractoriumEmberControllerBase > ( new FractoriumEmberController < float > ( this ) ) ;
2014-07-08 03:11:14 -04:00
2016-03-28 21:49:10 -04:00
m_Controller - > SetupVariationsTree ( ) ;
2015-08-10 23:10:23 -04:00
m_Controller - > FilteredVariations ( ) ;
2015-06-28 17:04:30 -04:00
--User changes
-Support 4k monitors, and in general, properly scale any monitor that is not HD.
-Allow for a spatial filter of radius zero, which means do not use a spatial filter.
-Add new variations: concentric, cpow3, helicoid, helix, rand_cubes, sphereblur.
-Use a new method for computing elliptic which is more precise. Developed by Discord user Claude.
-Remove the 8 variation per xform limitation on the GPU.
-Allow for loading the last flame file on startup, rather than randoms.
-Use two different default quality values in the interactive renderer, one each for CPU and GPU.
-Creating linked xforms was using non-standard behavior. Make it match Apo and also support creating multiple linked xforms at once.
--Bug fixes
-No variations in an xform used to have the same behavior as a single linear variation with weight 1. While sensible, this breaks backward compatibility. No variations now sets the output point to zeroes.
-Prevent crashing the program when adjusting a value on the main window while a final render is in progress.
-The xaos table was inverted.
--Code changes
-Convert projects to Visual Studio 2017.
-Change bad vals from +- 1e10 to +-1e20.
-Reintroduce the symmetry tag in xforms for legacy support in programs that do not use color_speed.
-Compiler will not let us use default values in templated member functions anymore.
2017-11-26 20:27:00 -05:00
if ( m_Info - > Ok ( ) & & m_Settings - > OpenCL ( ) & & m_QualitySpin - > value ( ) < ( m_Settings - > OpenClQuality ( ) * m_Settings - > Devices ( ) . size ( ) ) )
m_QualitySpin - > setValue ( m_Settings - > OpenClQuality ( ) * m_Settings - > Devices ( ) . size ( ) ) ;
2014-07-08 03:11:14 -04:00
--User changes
-Support 4k monitors, and in general, properly scale any monitor that is not HD.
-Allow for a spatial filter of radius zero, which means do not use a spatial filter.
-Add new variations: concentric, cpow3, helicoid, helix, rand_cubes, sphereblur.
-Use a new method for computing elliptic which is more precise. Developed by Discord user Claude.
-Remove the 8 variation per xform limitation on the GPU.
-Allow for loading the last flame file on startup, rather than randoms.
-Use two different default quality values in the interactive renderer, one each for CPU and GPU.
-Creating linked xforms was using non-standard behavior. Make it match Apo and also support creating multiple linked xforms at once.
--Bug fixes
-No variations in an xform used to have the same behavior as a single linear variation with weight 1. While sensible, this breaks backward compatibility. No variations now sets the output point to zeroes.
-Prevent crashing the program when adjusting a value on the main window while a final render is in progress.
-The xaos table was inverted.
--Code changes
-Convert projects to Visual Studio 2017.
-Change bad vals from +- 1e10 to +-1e20.
-Reintroduce the symmetry tag in xforms for legacy support in programs that do not use color_speed.
-Compiler will not let us use default values in templated member functions anymore.
2017-11-26 20:27:00 -05:00
int statusBarHeight = 20 ; // *devicePixelRatio();
2015-10-27 00:31:35 -04:00
ui . StatusBar - > setMinimumHeight ( statusBarHeight ) ;
ui . StatusBar - > setMaximumHeight ( statusBarHeight ) ;
2014-07-08 03:11:14 -04:00
m_RenderStatusLabel = new QLabel ( this ) ;
m_RenderStatusLabel - > setMinimumWidth ( 200 ) ;
m_RenderStatusLabel - > setAlignment ( Qt : : AlignRight ) ;
2015-10-27 00:31:35 -04:00
ui . StatusBar - > addPermanentWidget ( m_RenderStatusLabel ) ;
2014-07-08 03:11:14 -04:00
m_CoordinateStatusLabel = new QLabel ( this ) ;
m_CoordinateStatusLabel - > setMinimumWidth ( 300 ) ;
m_CoordinateStatusLabel - > setMaximumWidth ( 300 ) ;
m_CoordinateStatusLabel - > setAlignment ( Qt : : AlignLeft ) ;
2015-10-27 00:31:35 -04:00
ui . StatusBar - > addWidget ( m_CoordinateStatusLabel ) ;
2014-07-08 03:11:14 -04:00
int progressBarHeight = 15 ;
int progressBarWidth = 300 ;
m_ProgressBar = new QProgressBar ( this ) ;
m_ProgressBar - > setRange ( 0 , 100 ) ;
m_ProgressBar - > setValue ( 0 ) ;
m_ProgressBar - > setMinimumHeight ( progressBarHeight ) ;
m_ProgressBar - > setMaximumHeight ( progressBarHeight ) ;
m_ProgressBar - > setMinimumWidth ( progressBarWidth ) ;
m_ProgressBar - > setMaximumWidth ( progressBarWidth ) ;
2015-10-27 00:31:35 -04:00
ui . StatusBar - > addPermanentWidget ( m_ProgressBar ) ;
2015-01-01 10:17:05 -05:00
//Setup pointer in the GL window to point back to here.
ui . GLDisplay - > SetMainWindow ( this ) ;
2015-06-20 14:35:08 -04:00
bool restored = restoreState ( m_Settings - > value ( " windowState " ) . toByteArray ( ) ) ;
2015-01-02 18:11:36 -05:00
showMaximized ( ) ; //This won't fully set things up and show them until after this constructor exits.
2015-06-17 23:05:53 -04:00
connect ( ui . LibraryDockWidget , SIGNAL ( dockLocationChanged ( Qt : : DockWidgetArea ) ) , this , SLOT ( dockLocationChanged ( Qt : : DockWidgetArea ) ) ) ;
connect ( ui . LibraryDockWidget , SIGNAL ( topLevelChanged ( bool ) ) , this , SLOT ( OnDockTopLevelChanged ( bool ) ) ) ;
2015-12-31 16:41:59 -05:00
2016-04-03 21:55:12 -04:00
//Always ensure the library tab is selected if not restoring, which will show preview renders.
2015-06-20 14:35:08 -04:00
if ( ! restored )
{
ui . LibraryDockWidget - > raise ( ) ;
ui . LibraryDockWidget - > show ( ) ;
ui . XformsTabWidget - > setCurrentIndex ( 2 ) ; //Make variations tab the currently selected one under the Xforms tab.
}
2014-07-08 03:11:14 -04:00
m_PreviousPaletteRow = - 1 ; //Force click handler the first time through.
SetCoordinateStatus ( 0 , 0 , 0 , 0 ) ;
2014-07-28 01:25:38 -04:00
SetTabOrders ( ) ;
2015-10-27 00:31:35 -04:00
m_SettingsPath = QFileInfo ( m_Settings - > fileName ( ) ) . absoluteDir ( ) . absolutePath ( ) ;
ifstream ifs ( ( m_SettingsPath + " /default.qss " ) . toStdString ( ) . c_str ( ) , ifstream : : in ) ;
if ( ifs . is_open ( ) )
{
string total , qs ;
2016-12-05 22:04:33 -05:00
total . reserve ( 20 * 1024 ) ;
2015-10-27 00:31:35 -04:00
while ( std : : getline ( ifs , qs ) )
total + = qs + " \n " ;
m_Style = QString : : fromStdString ( total ) ;
}
else
m_Style = BaseStyle ( ) ;
setStyleSheet ( m_Style ) ;
if ( ! m_Settings - > Theme ( ) . isEmpty ( ) )
{
if ( auto theme = QStyleFactory : : create ( m_Settings - > Theme ( ) ) )
{
m_Theme = theme ;
setStyle ( m_Theme ) ;
}
}
else
{
if ( ! QStyleFactory : : keys ( ) . empty ( ) )
{
m_Theme = QStyleFactory : : create ( qApp - > style ( ) - > objectName ( ) ) ;
setStyle ( m_Theme ) ;
}
}
--User changes
-Add a palette editor.
-Add support for reading .ugr/.gradient/.gradients palette files.
-Allow toggling on spinners whose minimum value is not zero.
-Allow toggling display of image, affines and grid.
-Add new variations: cylinder2, circlesplit, tile_log, truchet_fill, waves2_radial.
--Bug fixes
-cpow2 was wrong.
-Palettes with rapid changes in color would produce slightly different outputs from Apo/Chaotica. This was due to a long standing bug from flam3.
-Use exec() on Apple and show() on all other OSes for dialog boxes.
-Trying to render a sequence with no frames would crash.
-Selecting multiple xforms and rotating them would produce the wrong rotation.
-Better handling when parsing flames using different encoding, such as unicode and UTF-8.
-Switching between SP/DP didn't reselect the selected flame in the Library tab.
--Code changes
-Make all types concerning palettes be floats, including PaletteTableWidgetItem.
-PaletteTableWidgetItem is no longer templated because all palettes are float.
-Include the source colors for user created gradients.
-Change parallel_for() calls to work with very old versions of TBB which are lingering on some systems.
-Split conditional out of accumulation loop on the CPU for better performance.
-Vectorize summing when doing density filter for better performance.
-Make all usage of palettes be of type float, double is pointless.
-Allow palettes to reside in multiple folders, while ensuring only one of each name is added.
-Refactor some palette path searching code.
-Make ReadFile() throw and catch an exception if the file operation fails.
-A little extra safety in foci and foci3D with a call to Zeps().
-Cast to (real_t) in the OpenCL string for the w variation, which was having trouble compiling on Mac.
-Fixing missing comma between paths in InitPaletteList().
-Move Xml and PaletteList classes into cpp to shorten build times when working on them.
-Remove default param values for IterOpenCLKernelCreator<T>::SharedDataIndexDefines in cpp file.
-Change more NULL to nullptr.
2017-02-26 03:02:21 -05:00
# ifdef __APPLE__
for ( auto dock : m_Docks ) //Fixes focus problem on OSX.
{
if ( ! dock - > isHidden ( ) )
{
dock - > setFloating ( ! dock - > isFloating ( ) ) ;
dock - > setFloating ( ! dock - > isFloating ( ) ) ;
break ;
}
}
# endif
2014-07-08 03:11:14 -04:00
//At this point, everything has been setup except the renderer. Shortly after
2015-01-02 18:11:36 -05:00
//this constructor exits, GLWidget::InitGL() will create the initial flock and start the rendering timer
2014-07-08 03:11:14 -04:00
//which executes whenever the program is idle. Upon starting the timer, the renderer
//will be initialized.
2018-04-29 01:28:05 -04:00
//auto cdc = wglGetCurrentDC();
//auto cc = wglGetCurrentContext();
//qDebug() << "Fractorium::Fractorium():";
//qDebug() << "Current DC: " << cdc;
//qDebug() << "Current Context: " << cc;
2018-01-28 20:51:19 -05:00
QTimer : : singleShot ( 1000 , [ & ] ( ) { ui . GLDisplay - > InitGL ( ) ; } ) ;
2014-07-08 03:11:14 -04:00
}
/// <summary>
/// Destructor which saves out the settings file.
/// All other memory is cleared automatically through the use of STL.
/// </summary>
Fractorium : : ~ Fractorium ( )
{
2016-06-11 20:47:03 -04:00
SyncSequenceSettings ( ) ;
2015-07-23 21:16:36 -04:00
m_VarDialog - > SyncSettings ( ) ;
--User changes
-Add a palette editor.
-Add support for reading .ugr/.gradient/.gradients palette files.
-Allow toggling on spinners whose minimum value is not zero.
-Allow toggling display of image, affines and grid.
-Add new variations: cylinder2, circlesplit, tile_log, truchet_fill, waves2_radial.
--Bug fixes
-cpow2 was wrong.
-Palettes with rapid changes in color would produce slightly different outputs from Apo/Chaotica. This was due to a long standing bug from flam3.
-Use exec() on Apple and show() on all other OSes for dialog boxes.
-Trying to render a sequence with no frames would crash.
-Selecting multiple xforms and rotating them would produce the wrong rotation.
-Better handling when parsing flames using different encoding, such as unicode and UTF-8.
-Switching between SP/DP didn't reselect the selected flame in the Library tab.
--Code changes
-Make all types concerning palettes be floats, including PaletteTableWidgetItem.
-PaletteTableWidgetItem is no longer templated because all palettes are float.
-Include the source colors for user created gradients.
-Change parallel_for() calls to work with very old versions of TBB which are lingering on some systems.
-Split conditional out of accumulation loop on the CPU for better performance.
-Vectorize summing when doing density filter for better performance.
-Make all usage of palettes be of type float, double is pointless.
-Allow palettes to reside in multiple folders, while ensuring only one of each name is added.
-Refactor some palette path searching code.
-Make ReadFile() throw and catch an exception if the file operation fails.
-A little extra safety in foci and foci3D with a call to Zeps().
-Cast to (real_t) in the OpenCL string for the w variation, which was having trouble compiling on Mac.
-Fixing missing comma between paths in InitPaletteList().
-Move Xml and PaletteList classes into cpp to shorten build times when working on them.
-Remove default param values for IterOpenCLKernelCreator<T>::SharedDataIndexDefines in cpp file.
-Change more NULL to nullptr.
2017-02-26 03:02:21 -05:00
m_Settings - > ShowXforms ( ui . ActionDrawXforms - > isChecked ( ) ) ;
m_Settings - > ShowGrid ( ui . ActionDrawGrid - > isChecked ( ) ) ;
2015-06-17 23:05:53 -04:00
m_Settings - > setValue ( " windowState " , saveState ( ) ) ;
2014-07-08 03:11:14 -04:00
m_Settings - > sync ( ) ;
--User changes
-Support 4k monitors, and in general, properly scale any monitor that is not HD.
-Allow for a spatial filter of radius zero, which means do not use a spatial filter.
-Add new variations: concentric, cpow3, helicoid, helix, rand_cubes, sphereblur.
-Use a new method for computing elliptic which is more precise. Developed by Discord user Claude.
-Remove the 8 variation per xform limitation on the GPU.
-Allow for loading the last flame file on startup, rather than randoms.
-Use two different default quality values in the interactive renderer, one each for CPU and GPU.
-Creating linked xforms was using non-standard behavior. Make it match Apo and also support creating multiple linked xforms at once.
--Bug fixes
-No variations in an xform used to have the same behavior as a single linear variation with weight 1. While sensible, this breaks backward compatibility. No variations now sets the output point to zeroes.
-Prevent crashing the program when adjusting a value on the main window while a final render is in progress.
-The xaos table was inverted.
--Code changes
-Convert projects to Visual Studio 2017.
-Change bad vals from +- 1e10 to +-1e20.
-Reintroduce the symmetry tag in xforms for legacy support in programs that do not use color_speed.
-Compiler will not let us use default values in templated member functions anymore.
2017-11-26 20:27:00 -05:00
if ( m_Settings - > LoadLast ( ) )
m_Controller - > SaveCurrentFileOnShutdown ( ) ;
2014-07-08 03:11:14 -04:00
}
/// <summary>
/// Set the coordinate text in the status bar.
/// </summary>
2014-12-11 00:50:15 -05:00
/// <param name="rasX">The raster x coordinate</param>
/// <param name="rasY">The raster y coordinate</param>
2014-07-08 03:11:14 -04:00
/// <param name="worldX">The cartesian world x coordinate</param>
/// <param name="worldY">The cartesian world y coordinate</param>
2014-12-11 00:50:15 -05:00
void Fractorium : : SetCoordinateStatus ( int rasX , int rasY , float worldX , float worldY )
2014-07-08 03:11:14 -04:00
{
2016-12-05 22:04:33 -05:00
static QString coords ;
coords . sprintf ( " Window: %4d, %4d World: %2.2f, %2.2f " , rasX , rasY , worldX , worldY ) ;
m_CoordinateStatusLabel - > setText ( coords ) ;
2014-07-08 03:11:14 -04:00
}
2015-01-02 18:11:36 -05:00
/// <summary>
/// Center the scroll area.
/// Called in response to a resizing, or setting of new ember.
/// </summary>
void Fractorium : : CenterScrollbars ( )
{
QScrollBar * w = ui . GLParentScrollArea - > horizontalScrollBar ( ) ;
QScrollBar * h = ui . GLParentScrollArea - > verticalScrollBar ( ) ;
w - > setValue ( w - > maximum ( ) / 2 ) ;
h - > setValue ( h - > maximum ( ) / 2 ) ;
}
2014-07-08 03:11:14 -04:00
/// <summary>
/// Apply the settings for saving an ember to an Xml file to an ember (presumably about to be saved).
/// </summary>
/// <param name="ember">The ember to apply the settings to</param>
template < typename T >
void FractoriumEmberController < T > : : ApplyXmlSavingTemplate ( Ember < T > & ember )
{
ember . m_Quality = m_Fractorium - > m_Settings - > XmlQuality ( ) ;
ember . m_Supersample = m_Fractorium - > m_Settings - > XmlSupersample ( ) ;
2014-10-14 11:53:15 -04:00
ember . m_TemporalSamples = m_Fractorium - > m_Settings - > XmlTemporalSamples ( ) ;
2014-07-08 03:11:14 -04:00
}
/// <summary>
/// Return whether the current ember contains a final xform and the GUI is aware of it.
2017-07-27 00:25:44 -04:00
/// Note this can be true even if the final is empty, as long as they've added one and have
/// not explicitly deleted it.
2014-07-08 03:11:14 -04:00
/// </summary>
/// <returns>True if the current ember contains a final xform, else false.</returns>
bool Fractorium : : HaveFinal ( )
{
2016-02-02 20:51:58 -05:00
auto combo = ui . CurrentXformCombo ;
2014-07-08 03:11:14 -04:00
return ( combo - > count ( ) > 0 & & combo - > itemText ( combo - > count ( ) - 1 ) = = " Final " ) ;
}
/// <summary>
/// Slots.
/// </summary>
/// <summary>
/// Empty placeholder for now.
/// Qt has a severe bug where the dock gets hidden behind the window.
/// Perhaps this will be used in the future if Qt ever fixes that bug.
/// Called when the top level dock is changed.
/// </summary>
/// <param name="topLevel">True if top level, else false.</param>
void Fractorium : : OnDockTopLevelChanged ( bool topLevel )
{
2017-12-16 00:05:58 -05:00
//setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::TabPosition::North);
2014-07-08 03:11:14 -04:00
//if (topLevel)
//{
// if (ui.DockWidget->y() <= 0)
// ui.DockWidget->setGeometry(ui.DockWidget->x(), ui.DockWidget->y() + 100, ui.DockWidget->width(), ui.DockWidget->height());
//
// ui.DockWidget->setFloating(true);
//}
//else
// ui.DockWidget->setFloating(false);
}
/// <summary>
/// Empty placeholder for now.
/// Qt has a severe bug where the dock gets hidden behind the window.
/// Perhaps this will be used in the future if Qt ever fixes that bug.
/// Called when the dock location is changed.
/// </summary>
/// <param name="area">The dock widget area</param>
void Fractorium : : dockLocationChanged ( Qt : : DockWidgetArea area )
{
2017-12-16 00:05:58 -05:00
//setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::TabPosition::North);
2014-07-08 03:11:14 -04:00
//ui.DockWidget->resize(500, ui.DockWidget->height());
//ui.DockWidget->update();
//ui.dockWidget->setFloating(true);
//ui.dockWidget->setFloating(false);
}
/// <summary>
/// Virtual event overrides.
/// </summary>
/// <summary>
2015-03-21 18:27:37 -04:00
/// Event filter for taking special action on:
/// Dock widget resize events, which in turn trigger GLParentScrollArea events.
/// Library tree key events, specifically delete.
2016-04-03 21:55:12 -04:00
/// Library tree drag n drop events.
2014-07-08 03:11:14 -04:00
/// </summary>
2014-12-12 03:54:03 -05:00
/// <param name="o">The object</param>
/// <param name="e">The eevent</param>
/// <returns>false</returns>
bool Fractorium : : eventFilter ( QObject * o , QEvent * e )
{
2018-07-31 00:39:41 -04:00
static int fcount = 0 ; //Qt seems to deliver three events for every key press. So a count must be kept to only respond to the third event.
static int libdelcount = 0 ; //Note that if anything ever changes under the hood with Qt, this will likely stop working, so adjust as accordingly.
static int xfupcount = 0 ;
static int xfdncount = 0 ;
2014-12-12 03:54:03 -05:00
if ( o = = ui . GLParentScrollArea & & e - > type ( ) = = QEvent : : Resize )
{
--User changes
-Support 4k monitors, and in general, properly scale any monitor that is not HD.
-Allow for a spatial filter of radius zero, which means do not use a spatial filter.
-Add new variations: concentric, cpow3, helicoid, helix, rand_cubes, sphereblur.
-Use a new method for computing elliptic which is more precise. Developed by Discord user Claude.
-Remove the 8 variation per xform limitation on the GPU.
-Allow for loading the last flame file on startup, rather than randoms.
-Use two different default quality values in the interactive renderer, one each for CPU and GPU.
-Creating linked xforms was using non-standard behavior. Make it match Apo and also support creating multiple linked xforms at once.
--Bug fixes
-No variations in an xform used to have the same behavior as a single linear variation with weight 1. While sensible, this breaks backward compatibility. No variations now sets the output point to zeroes.
-Prevent crashing the program when adjusting a value on the main window while a final render is in progress.
-The xaos table was inverted.
--Code changes
-Convert projects to Visual Studio 2017.
-Change bad vals from +- 1e10 to +-1e20.
-Reintroduce the symmetry tag in xforms for legacy support in programs that do not use color_speed.
-Compiler will not let us use default values in templated member functions anymore.
2017-11-26 20:27:00 -05:00
m_WidthSpin - > DoubleClickNonZero ( ui . GLParentScrollArea - > width ( ) * ui . GLDisplay - > devicePixelRatioF ( ) ) ;
m_HeightSpin - > DoubleClickNonZero ( ui . GLParentScrollArea - > height ( ) * ui . GLDisplay - > devicePixelRatioF ( ) ) ;
2014-12-12 03:54:03 -05:00
}
2016-04-03 21:55:12 -04:00
else if ( auto ke = dynamic_cast < QKeyEvent * > ( e ) )
2015-03-21 18:27:37 -04:00
{
2018-07-31 00:39:41 -04:00
auto combo = ui . CurrentXformCombo ;
--User changes
-Add new variations: bubbleT3D, crob, hexaplay3D, hexcrop, hexes, hexnix3D, loonie2, loonie3, nBlur, octapol and synth.
-Allow for pre/post versions of dc_bubble, dc_cylinder and dc_linear whereas before they were omitted.
-When saving a file with multiple embers in it, detect if time values are all the same and if so, start them at zero and increment by 1 for each ember.
-Allow for numerous quality increases to be coalesced into one. It will pick up at the end of the current render.
-Show selection highlight on variations tree in response to mouse hover. This makes it easier to see for which variation or param the current mouse wheel action will apply.
-Make default temporal samples be 100, whereas before it was 1000 which was overkill.
-Require the shift key to be held with delete for deleting an ember to prevent it from triggering when the user enters delete in the edit box.
-This wasn't otherwise fixable without writing a lot more code.
--Bug fixes
-EmberGenome was crashing when generating a sequence from a source file with more than 2 embers in it.
-EmberGenome was improperly handling the first frame of a merge after the last frame of the loop.
-These bugs were due to a previous commit. Revert parts of that commit.
-Prevent a zoom value of less than 0 when reading from xml.
-Slight optimization of the crescents, and mask variations, if the compiler wasn't doing it already.
-Unique file naming was broken because it was looking for _# and the default names ended with -#.
-Disallow renaming of an ember in the library tree to an empty string.
-Severe bug that prevented some variations from being read correctly from params generated outside this program.
-Severe OpenCL randomization bug. The first x coordinates of the first points in the first kernel call of the first ember of a render since the OpenCL renderer object was created were not random and were mostly -1.
-Severe bug when populating xform selection distributions that could sometimes cause a crash due to roundoff error. Fix by using double.
-Limit the max number of variations in a random ember to MAX_CL_VARS, which is 8. This ensures they'll look the same on CPU and GPU.
-Prevent user from saving stylesheet to default.qss, it's a special reserved filename.
--Code changes
-Generalize using the running sum output point inside of a variation for all cases: pre, reg and post.
-Allow for array variables in variations where the address of each element is stored in m_Params.
-Qualify all math functions with std::
-No longer use our own Clamp() in OpenCL, instead use the standard clamp().
-Redesign how functions are used in the variations OpenCL code.
-Add tests to EmberTester to verify some of the new functionality.
-Place more const and override qualifiers on functions where appropriate.
-Add a global rand with a lock to be used very sparingly.
-Use a map instead of a vector for bad param names in Xml parsing.
-Prefix affine interpolation mode defines with "AFFINE_" to make their purpose more clear.
-Allow for variations that change state during iteration by sending a separate copy of the ember to each rendering thread.
-Implement this same functionality with a local struct in OpenCL. It's members are the total of all variables that need to change state within an ember.
-Add Contains() function to Utils.h.
-EmberRender: print names of kernels being printed with --dump_kernel option.
-Clean up EmberTester to handle some of the recent changes.
-Fix various casts.
-Replace % 2 with & 1, even though the compiler was likely doing this already.
-Add new file Variations06.h to accommodate new variations.
-General cleanup.
2015-11-22 17:15:07 -05:00
bool shift = QGuiApplication : : keyboardModifiers ( ) . testFlag ( Qt : : ShiftModifier ) ;
2015-05-03 20:13:14 -04:00
if ( ke - > key ( ) > = Qt : : Key_F1 & & ke - > key ( ) < = Qt : : Key_F32 )
{
2018-07-31 00:39:41 -04:00
fcount + + ;
if ( fcount > = 3 )
{
int val = ke - > key ( ) - ( int ) Qt : : Key_F1 ;
if ( val < combo - > count ( ) )
combo - > setCurrentIndex ( val ) ;
fcount = 0 ;
2018-09-22 01:42:18 -04:00
//qDebug() << "global function key press: " << ke->key() << " " << o->metaObject()->className() << " " << o->objectName();
2018-07-31 00:39:41 -04:00
}
2015-05-03 20:13:14 -04:00
2018-07-31 00:39:41 -04:00
return true ;
2015-05-03 20:13:14 -04:00
}
else if ( o = = ui . LibraryTree )
2015-03-21 18:27:37 -04:00
{
--User changes
-Add new variations: bubbleT3D, crob, hexaplay3D, hexcrop, hexes, hexnix3D, loonie2, loonie3, nBlur, octapol and synth.
-Allow for pre/post versions of dc_bubble, dc_cylinder and dc_linear whereas before they were omitted.
-When saving a file with multiple embers in it, detect if time values are all the same and if so, start them at zero and increment by 1 for each ember.
-Allow for numerous quality increases to be coalesced into one. It will pick up at the end of the current render.
-Show selection highlight on variations tree in response to mouse hover. This makes it easier to see for which variation or param the current mouse wheel action will apply.
-Make default temporal samples be 100, whereas before it was 1000 which was overkill.
-Require the shift key to be held with delete for deleting an ember to prevent it from triggering when the user enters delete in the edit box.
-This wasn't otherwise fixable without writing a lot more code.
--Bug fixes
-EmberGenome was crashing when generating a sequence from a source file with more than 2 embers in it.
-EmberGenome was improperly handling the first frame of a merge after the last frame of the loop.
-These bugs were due to a previous commit. Revert parts of that commit.
-Prevent a zoom value of less than 0 when reading from xml.
-Slight optimization of the crescents, and mask variations, if the compiler wasn't doing it already.
-Unique file naming was broken because it was looking for _# and the default names ended with -#.
-Disallow renaming of an ember in the library tree to an empty string.
-Severe bug that prevented some variations from being read correctly from params generated outside this program.
-Severe OpenCL randomization bug. The first x coordinates of the first points in the first kernel call of the first ember of a render since the OpenCL renderer object was created were not random and were mostly -1.
-Severe bug when populating xform selection distributions that could sometimes cause a crash due to roundoff error. Fix by using double.
-Limit the max number of variations in a random ember to MAX_CL_VARS, which is 8. This ensures they'll look the same on CPU and GPU.
-Prevent user from saving stylesheet to default.qss, it's a special reserved filename.
--Code changes
-Generalize using the running sum output point inside of a variation for all cases: pre, reg and post.
-Allow for array variables in variations where the address of each element is stored in m_Params.
-Qualify all math functions with std::
-No longer use our own Clamp() in OpenCL, instead use the standard clamp().
-Redesign how functions are used in the variations OpenCL code.
-Add tests to EmberTester to verify some of the new functionality.
-Place more const and override qualifiers on functions where appropriate.
-Add a global rand with a lock to be used very sparingly.
-Use a map instead of a vector for bad param names in Xml parsing.
-Prefix affine interpolation mode defines with "AFFINE_" to make their purpose more clear.
-Allow for variations that change state during iteration by sending a separate copy of the ember to each rendering thread.
-Implement this same functionality with a local struct in OpenCL. It's members are the total of all variables that need to change state within an ember.
-Add Contains() function to Utils.h.
-EmberRender: print names of kernels being printed with --dump_kernel option.
-Clean up EmberTester to handle some of the recent changes.
-Fix various casts.
-Replace % 2 with & 1, even though the compiler was likely doing this already.
-Add new file Variations06.h to accommodate new variations.
-General cleanup.
2015-11-22 17:15:07 -05:00
//Require shift for deleting to prevent it from triggering when the user enters delete in the edit box.
if ( ke - > key ( ) = = Qt : : Key_Delete & & e - > type ( ) = = QEvent : : KeyRelease & & shift )
2015-03-21 18:27:37 -04:00
{
2018-07-31 00:39:41 -04:00
libdelcount + + ;
if ( libdelcount > = 3 )
{
auto v = GetCurrentEmberIndex ( ) ;
if ( ui . LibraryTree - > topLevelItem ( 0 ) - > childCount ( ) > 1 )
OnDelete ( v ) ;
libdelcount = 0 ;
}
return true ;
}
}
else if ( o = = this )
{
2018-09-30 17:20:02 -04:00
auto focusedctrl = dynamic_cast < QSpinBox * > ( this - > focusWidget ( ) ) ;
2018-07-31 00:39:41 -04:00
2018-09-30 17:20:02 -04:00
if ( ! focusedctrl ) //Doesn't seem to matter, but just to be safe.
2018-07-31 00:39:41 -04:00
{
2018-09-30 17:20:02 -04:00
unsigned int index = combo - > currentIndex ( ) ;
2018-07-31 00:39:41 -04:00
2018-09-30 17:20:02 -04:00
if ( ke - > key ( ) = = Qt : : Key_Plus | | ke - > key ( ) = = Qt : : Key_Equal )
2018-07-31 00:39:41 -04:00
{
2018-09-30 17:20:02 -04:00
xfupcount + + ;
2018-07-31 00:39:41 -04:00
2018-09-30 17:20:02 -04:00
if ( xfupcount > = 3 )
{
xfupcount = 0 ;
combo - > setCurrentIndex ( ( index + 1 ) % combo - > count ( ) ) ;
//qDebug() << "global arrow plus key press: " << ke->key() << " " << o->metaObject()->className() << " " << o->objectName();
}
2018-07-31 00:39:41 -04:00
2018-09-30 17:20:02 -04:00
return true ;
}
else if ( ke - > key ( ) = = Qt : : Key_Minus | | ke - > key ( ) = = Qt : : Key_Underscore )
2018-07-31 00:39:41 -04:00
{
2018-09-30 17:20:02 -04:00
xfdncount + + ;
2018-07-31 00:39:41 -04:00
2018-09-30 17:20:02 -04:00
if ( xfdncount > = 3 )
{
xfdncount = 0 ;
2018-07-31 00:39:41 -04:00
2018-09-30 17:20:02 -04:00
if ( index = = 0 )
index = combo - > count ( ) ;
2015-03-21 18:27:37 -04:00
2018-09-30 17:20:02 -04:00
combo - > setCurrentIndex ( ( index - 1 ) % combo - > count ( ) ) ;
//qDebug() << "global arrow minus key press: " << ke->key() << " " << o->metaObject()->className() << " " << o->objectName();
}
return true ;
}
2015-03-21 18:27:37 -04:00
}
}
}
2014-12-12 03:54:03 -05:00
return QMainWindow : : eventFilter ( o , e ) ;
}
/// <summary>
/// Respond to a resize event which will set the double click default value
/// in the width and height spinners.
/// Note, this does not change the size of the ember being rendered or
/// the OpenGL texture it's being drawn on.
2014-07-08 03:11:14 -04:00
/// <param name="e">The event</param>
void Fractorium : : resizeEvent ( QResizeEvent * e )
{
--User changes
-Support 4k monitors, and in general, properly scale any monitor that is not HD.
-Allow for a spatial filter of radius zero, which means do not use a spatial filter.
-Add new variations: concentric, cpow3, helicoid, helix, rand_cubes, sphereblur.
-Use a new method for computing elliptic which is more precise. Developed by Discord user Claude.
-Remove the 8 variation per xform limitation on the GPU.
-Allow for loading the last flame file on startup, rather than randoms.
-Use two different default quality values in the interactive renderer, one each for CPU and GPU.
-Creating linked xforms was using non-standard behavior. Make it match Apo and also support creating multiple linked xforms at once.
--Bug fixes
-No variations in an xform used to have the same behavior as a single linear variation with weight 1. While sensible, this breaks backward compatibility. No variations now sets the output point to zeroes.
-Prevent crashing the program when adjusting a value on the main window while a final render is in progress.
-The xaos table was inverted.
--Code changes
-Convert projects to Visual Studio 2017.
-Change bad vals from +- 1e10 to +-1e20.
-Reintroduce the symmetry tag in xforms for legacy support in programs that do not use color_speed.
-Compiler will not let us use default values in templated member functions anymore.
2017-11-26 20:27:00 -05:00
m_WidthSpin - > DoubleClickNonZero ( ui . GLParentScrollArea - > width ( ) * ui . GLDisplay - > devicePixelRatioF ( ) ) ;
m_HeightSpin - > DoubleClickNonZero ( ui . GLParentScrollArea - > height ( ) * ui . GLDisplay - > devicePixelRatioF ( ) ) ;
2014-07-08 03:11:14 -04:00
QMainWindow : : resizeEvent ( e ) ;
}
2015-07-29 09:55:55 -04:00
/// <summary>
/// Respond to a show event to ensure Qt updates the native menubar.
/// On first create, Qt can fail to create the native menu bar properly,
/// but telling it that this window has become the focus window forces
/// it to refresh this.
/// <param name="e">The event</param>
2015-12-31 16:41:59 -05:00
void Fractorium : : showEvent ( QShowEvent * e )
2015-07-29 09:55:55 -04:00
{
2015-07-31 22:46:53 -04:00
//Tell Qt to refresh the native menubar from this widget.
2015-07-29 09:55:55 -04:00
emit qGuiApp - > focusWindowChanged ( windowHandle ( ) ) ;
QMainWindow : : showEvent ( e ) ;
}
2014-07-08 03:11:14 -04:00
/// <summary>
/// Stop rendering and block before exiting.
/// Called on program exit.
/// </summary>
/// <param name="e">The event</param>
void Fractorium : : closeEvent ( QCloseEvent * e )
{
if ( m_Controller . get ( ) )
{
m_Controller - > StopRenderTimer ( true ) ; //Will wait until fully exited and stopped.
2016-06-11 20:47:03 -04:00
m_Controller - > StopAllPreviewRenderers ( ) ;
2014-07-08 03:11:14 -04:00
}
if ( e )
e - > accept ( ) ;
}
/// <summary>
/// Examine the files dragged when it first enters the window area.
/// Ok if at least one file is .flam3, .flam3 or .xml, else not ok.
/// Called when the user first drags files in.
/// </summary>
/// <param name="e">The event</param>
void Fractorium : : dragEnterEvent ( QDragEnterEvent * e )
{
if ( e - > mimeData ( ) - > hasUrls ( ) )
{
2016-02-02 20:51:58 -05:00
auto urls = e - > mimeData ( ) - > urls ( ) ;
for ( auto & url : urls )
2014-07-08 03:11:14 -04:00
{
QString localFile = url . toLocalFile ( ) ;
QFileInfo fileInfo ( localFile ) ;
QString suf = fileInfo . suffix ( ) ;
if ( suf = = " flam3 " | | suf = = " flame " | | suf = = " xml " )
{
e - > accept ( ) ;
break ;
}
}
}
}
/// <summary>
/// Always accept drag when moving, so that the drop event will correctly be called.
/// </summary>
/// <param name="e">The event</param>
void Fractorium : : dragMoveEvent ( QDragMoveEvent * e )
{
e - > accept ( ) ;
}
/// <summary>
/// Examine and open the dropped files.
/// Called when the user drops a file in.
/// </summary>
/// <param name="e">The event</param>
void Fractorium : : dropEvent ( QDropEvent * e )
{
QStringList filenames ;
Qt : : KeyboardModifiers mod = e - > keyboardModifiers ( ) ;
2016-03-28 21:49:10 -04:00
bool append = mod . testFlag ( Qt : : ControlModifier ) ? false : true ;
2014-07-08 03:11:14 -04:00
if ( e - > mimeData ( ) - > hasUrls ( ) )
{
2016-02-02 20:51:58 -05:00
auto urls = e - > mimeData ( ) - > urls ( ) ;
for ( auto & url : urls )
2014-07-08 03:11:14 -04:00
{
QString localFile = url . toLocalFile ( ) ;
QFileInfo fileInfo ( localFile ) ;
QString suf = fileInfo . suffix ( ) ;
if ( suf = = " flam3 " | | suf = = " flame " | | suf = = " xml " )
filenames < < localFile ;
}
}
if ( ! filenames . empty ( ) )
m_Controller - > OpenAndPrepFiles ( filenames , append ) ;
}
/// <summary>
/// Setup a combo box to be placed in a table cell.
/// </summary>
/// <param name="table">The table the combo box belongs to</param>
/// <param name="receiver">The receiver object</param>
/// <param name="row">The row in the table where this combo box resides</param>
/// <param name="col">The col in the table where this combo box resides</param>
/// <param name="comboBox">Double pointer to combo box which will hold the spinner upon exit</param>
/// <param name="vals">The string values to populate the combo box with</param>
/// <param name="signal">The signal the combo box emits</param>
/// <param name="slot">The slot to receive the signal</param>
/// <param name="connectionType">Type of the connection. Default: Qt::QueuedConnection.</param>
2015-05-03 20:13:14 -04:00
void Fractorium : : SetupCombo ( QTableWidget * table , const QObject * receiver , int & row , int col , StealthComboBox * & comboBox , const vector < string > & vals , const char * signal , const char * slot , Qt : : ConnectionType connectionType )
2014-07-08 03:11:14 -04:00
{
comboBox = new StealthComboBox ( table ) ;
2015-12-31 16:41:59 -05:00
2015-05-03 20:13:14 -04:00
for ( auto & s : vals ) comboBox - > addItem ( s . c_str ( ) ) ;
2015-12-31 16:41:59 -05:00
2014-07-08 03:11:14 -04:00
table - > setCellWidget ( row , col , comboBox ) ;
connect ( comboBox , signal , receiver , slot , connectionType ) ;
row + + ;
}
/// <summary>
/// Set the header of a table to be fixed.
/// </summary>
/// <param name="header">The header to set</param>
/// <param name="mode">The resizing mode to use. Default: QHeaderView::Fixed.</param>
void Fractorium : : SetFixedTableHeader ( QHeaderView * header , QHeaderView : : ResizeMode mode )
{
header - > setVisible ( true ) ; //For some reason, the designer keeps clobbering this value, so force it here.
header - > setSectionsClickable ( false ) ;
header - > setSectionResizeMode ( mode ) ;
}
/// <summary>
/// Setup and show the open XML dialog.
/// This will perform lazy instantiation.
/// </summary>
2017-07-22 16:43:35 -04:00
/// <returns>The list of filenames selected</returns>
2014-07-08 03:11:14 -04:00
QStringList Fractorium : : SetupOpenXmlDialog ( )
{
2017-04-04 19:21:58 -04:00
# ifndef __APPLE__
2014-07-08 03:11:14 -04:00
//Lazy instantiate since it takes a long time.
if ( ! m_FileDialog )
{
m_FileDialog = new QFileDialog ( this ) ;
m_FileDialog - > setViewMode ( QFileDialog : : List ) ;
2018-09-30 17:20:02 -04:00
m_FileDialog - > setOption ( QFileDialog : : DontUseNativeDialog , true ) ;
2014-07-08 03:11:14 -04:00
}
2015-12-31 16:41:59 -05:00
2014-07-08 03:11:14 -04:00
QStringList filenames ;
m_FileDialog - > disconnect ( SIGNAL ( filterSelected ( const QString & ) ) ) ;
2016-04-03 21:55:12 -04:00
connect ( m_FileDialog , & QFileDialog : : filterSelected , [ & ] ( const QString & filter ) { m_Settings - > OpenXmlExt ( filter ) ; } ) ;
2014-07-08 03:11:14 -04:00
m_FileDialog - > setFileMode ( QFileDialog : : ExistingFiles ) ;
m_FileDialog - > setAcceptMode ( QFileDialog : : AcceptOpen ) ;
2018-08-10 21:06:04 -04:00
m_FileDialog - > setNameFilter ( " Flam3 (*.flam3);;Flame (*.flame);;Xml (*.xml) " ) ;
--User changes
-Add a palette editor.
-Add support for reading .ugr/.gradient/.gradients palette files.
-Allow toggling on spinners whose minimum value is not zero.
-Allow toggling display of image, affines and grid.
-Add new variations: cylinder2, circlesplit, tile_log, truchet_fill, waves2_radial.
--Bug fixes
-cpow2 was wrong.
-Palettes with rapid changes in color would produce slightly different outputs from Apo/Chaotica. This was due to a long standing bug from flam3.
-Use exec() on Apple and show() on all other OSes for dialog boxes.
-Trying to render a sequence with no frames would crash.
-Selecting multiple xforms and rotating them would produce the wrong rotation.
-Better handling when parsing flames using different encoding, such as unicode and UTF-8.
-Switching between SP/DP didn't reselect the selected flame in the Library tab.
--Code changes
-Make all types concerning palettes be floats, including PaletteTableWidgetItem.
-PaletteTableWidgetItem is no longer templated because all palettes are float.
-Include the source colors for user created gradients.
-Change parallel_for() calls to work with very old versions of TBB which are lingering on some systems.
-Split conditional out of accumulation loop on the CPU for better performance.
-Vectorize summing when doing density filter for better performance.
-Make all usage of palettes be of type float, double is pointless.
-Allow palettes to reside in multiple folders, while ensuring only one of each name is added.
-Refactor some palette path searching code.
-Make ReadFile() throw and catch an exception if the file operation fails.
-A little extra safety in foci and foci3D with a call to Zeps().
-Cast to (real_t) in the OpenCL string for the w variation, which was having trouble compiling on Mac.
-Fixing missing comma between paths in InitPaletteList().
-Move Xml and PaletteList classes into cpp to shorten build times when working on them.
-Remove default param values for IterOpenCLKernelCreator<T>::SharedDataIndexDefines in cpp file.
-Change more NULL to nullptr.
2017-02-26 03:02:21 -05:00
m_FileDialog - > setWindowTitle ( " Open Flame " ) ;
2014-07-08 03:11:14 -04:00
m_FileDialog - > setDirectory ( m_Settings - > OpenFolder ( ) ) ;
m_FileDialog - > selectNameFilter ( m_Settings - > OpenXmlExt ( ) ) ;
if ( m_FileDialog - > exec ( ) = = QDialog : : Accepted )
{
filenames = m_FileDialog - > selectedFiles ( ) ;
if ( ! filenames . empty ( ) )
m_Settings - > OpenFolder ( QFileInfo ( filenames [ 0 ] ) . canonicalPath ( ) ) ;
}
2017-04-04 19:21:58 -04:00
# else
auto defaultFilter ( m_Settings - > OpenXmlExt ( ) ) ;
2018-08-10 21:06:04 -04:00
auto filenames = QFileDialog : : getOpenFileNames ( this , tr ( " Open Flame " ) , m_Settings - > OpenFolder ( ) , tr ( " Flam3(*.flam3);; Flame(*.flame);; Xml(*.xml) " ) , & defaultFilter ) ;
2017-04-04 19:21:58 -04:00
m_Settings - > OpenXmlExt ( defaultFilter ) ;
if ( ! filenames . empty ( ) )
m_Settings - > OpenFolder ( QFileInfo ( filenames [ 0 ] ) . canonicalPath ( ) ) ;
# endif
2014-07-08 03:11:14 -04:00
return filenames ;
}
/// <summary>
/// Setup and show the save XML dialog.
/// This will perform lazy instantiation.
/// </summary>
/// <param name="defaultFilename">The default filename to populate the text box with</param>
/// <returns>The filename selected</returns>
2014-10-14 11:53:15 -04:00
QString Fractorium : : SetupSaveXmlDialog ( const QString & defaultFilename )
2014-07-08 03:11:14 -04:00
{
2017-04-04 19:21:58 -04:00
# ifndef __APPLE__
2014-07-08 03:11:14 -04:00
//Lazy instantiate since it takes a long time.
2016-04-03 21:55:12 -04:00
//QS
2014-07-08 03:11:14 -04:00
if ( ! m_FileDialog )
{
m_FileDialog = new QFileDialog ( this ) ;
m_FileDialog - > setViewMode ( QFileDialog : : List ) ;
2018-09-30 17:20:02 -04:00
m_FileDialog - > setOption ( QFileDialog : : DontUseNativeDialog , true ) ;
2014-07-08 03:11:14 -04:00
}
2015-12-31 16:41:59 -05:00
2014-07-08 03:11:14 -04:00
QString filename ;
m_FileDialog - > disconnect ( SIGNAL ( filterSelected ( const QString & ) ) ) ;
2017-07-22 16:43:35 -04:00
connect ( m_FileDialog , & QFileDialog : : filterSelected , [ & ] ( const QString & filter )
{
m_Settings - > SaveXmlExt ( filter ) ;
m_FileDialog - > setDefaultSuffix ( filter ) ;
} ) ;
2014-07-08 03:11:14 -04:00
//This must come first because it clears various internal states which allow the file text to be properly set.
//This is most likely a bug in QFileDialog.
m_FileDialog - > setAcceptMode ( QFileDialog : : AcceptSave ) ;
m_FileDialog - > selectFile ( defaultFilename ) ;
2018-10-20 21:40:46 -04:00
m_FileDialog - > setNameFilter ( " flam3 (*.flam3);;flame (*.flame);;xml (*.xml) " ) ;
2014-07-08 03:11:14 -04:00
m_FileDialog - > setWindowTitle ( " Save flame as xml " ) ;
m_FileDialog - > setDirectory ( m_Settings - > SaveFolder ( ) ) ;
m_FileDialog - > selectNameFilter ( m_Settings - > SaveXmlExt ( ) ) ;
2017-07-22 16:43:35 -04:00
m_FileDialog - > setDefaultSuffix ( m_Settings - > SaveXmlExt ( ) ) ;
2014-07-08 03:11:14 -04:00
if ( m_FileDialog - > exec ( ) = = QDialog : : Accepted )
2018-10-20 21:40:46 -04:00
{
2014-07-08 03:11:14 -04:00
filename = m_FileDialog - > selectedFiles ( ) . value ( 0 ) ;
2018-10-20 21:40:46 -04:00
auto filenames = filename . split ( " (* " ) ; //This is a total hack, but Qt has the unfortunate behavior of including the description with the extension. It's probably a bug.
filename = filenames [ 0 ] ;
m_Settings - > SaveXmlExt ( m_FileDialog - > selectedNameFilter ( ) ) ;
}
2014-07-08 03:11:14 -04:00
2017-04-04 19:21:58 -04:00
# else
auto defaultFilter ( m_Settings - > SaveXmlExt ( ) ) ;
auto filename = QFileDialog : : getSaveFileName ( this , tr ( " Save flame as xml " ) , m_Settings - > SaveFolder ( ) + " / " + defaultFilename , tr ( " Flam3 (*.flam3);;Flame (*.flame);;Xml (*.xml) " ) , & defaultFilter ) ;
m_Settings - > SaveXmlExt ( defaultFilter ) ;
# endif
2014-07-08 03:11:14 -04:00
return filename ;
}
/// <summary>
/// Setup and show the save image dialog.
/// This will perform lazy instantiation.
/// </summary>
/// <param name="defaultFilename">The default filename to populate the text box with</param>
/// <returns>The filename selected</returns>
2014-10-14 11:53:15 -04:00
QString Fractorium : : SetupSaveImageDialog ( const QString & defaultFilename )
2014-07-08 03:11:14 -04:00
{
2017-04-04 19:21:58 -04:00
# ifndef __APPLE__
2014-07-08 03:11:14 -04:00
//Lazy instantiate since it takes a long time.
if ( ! m_FileDialog )
{
m_FileDialog = new QFileDialog ( this ) ;
m_FileDialog - > setViewMode ( QFileDialog : : List ) ;
2018-09-30 17:20:02 -04:00
m_FileDialog - > setOption ( QFileDialog : : DontUseNativeDialog , true ) ;
2014-07-08 03:11:14 -04:00
}
2015-12-31 16:41:59 -05:00
2014-07-08 03:11:14 -04:00
QString filename ;
m_FileDialog - > disconnect ( SIGNAL ( filterSelected ( const QString & ) ) ) ;
2017-07-22 16:43:35 -04:00
connect ( m_FileDialog , & QFileDialog : : filterSelected , [ & ] ( const QString & filter )
{
m_Settings - > SaveImageExt ( filter ) ;
m_FileDialog - > setDefaultSuffix ( filter ) ;
} ) ;
2014-07-08 03:11:14 -04:00
//This must come first because it clears various internal states which allow the file text to be properly set.
//This is most likely a bug in QFileDialog.
m_FileDialog - > setAcceptMode ( QFileDialog : : AcceptSave ) ;
m_FileDialog - > selectFile ( defaultFilename ) ;
m_FileDialog - > setFileMode ( QFileDialog : : AnyFile ) ;
m_FileDialog - > setOption ( QFileDialog : : ShowDirsOnly , false ) ;
2017-07-22 16:43:35 -04:00
# ifdef _WIN32
m_FileDialog - > setNameFilter ( " .bmp;;.jpg;;.png;;.exr " ) ;
# else
m_FileDialog - > setNameFilter ( " .jpg;;.png;;.exr " ) ;
# endif
2014-07-08 03:11:14 -04:00
m_FileDialog - > setWindowTitle ( " Save image " ) ;
m_FileDialog - > setDirectory ( m_Settings - > SaveFolder ( ) ) ;
m_FileDialog - > selectNameFilter ( m_Settings - > SaveImageExt ( ) ) ;
2017-07-22 16:43:35 -04:00
m_FileDialog - > setDefaultSuffix ( m_Settings - > SaveImageExt ( ) ) ;
2014-07-08 03:11:14 -04:00
if ( m_FileDialog - > exec ( ) = = QDialog : : Accepted )
filename = m_FileDialog - > selectedFiles ( ) . value ( 0 ) ;
2017-04-04 19:21:58 -04:00
# else
auto defaultFilter ( m_Settings - > SaveImageExt ( ) ) ;
2017-07-22 16:43:35 -04:00
auto filename = QFileDialog : : getSaveFileName ( this , tr ( " Save image " ) , m_Settings - > SaveFolder ( ) + " / " + defaultFilename , tr ( " Jpg (*.jpg);;Png (*.png);;Exr (*.exr) " ) , & defaultFilter ) ;
2017-04-04 19:21:58 -04:00
m_Settings - > SaveImageExt ( defaultFilter ) ;
# endif
2014-07-08 03:11:14 -04:00
return filename ;
}
/// <summary>
/// Setup and show the save folder dialog.
/// This will perform lazy instantiation.
/// </summary>
2014-10-14 11:53:15 -04:00
/// <returns>The folder selected, with '/' appended to the end</returns>
2014-07-08 03:11:14 -04:00
QString Fractorium : : SetupSaveFolderDialog ( )
{
2017-04-04 19:21:58 -04:00
# ifndef __APPLE__
2014-07-08 03:11:14 -04:00
//Lazy instantiate since it takes a long time.
if ( ! m_FolderDialog )
{
m_FolderDialog = new QFileDialog ( this ) ;
m_FolderDialog - > setViewMode ( QFileDialog : : List ) ;
2018-09-30 17:20:02 -04:00
m_FolderDialog - > setOption ( QFileDialog : : DontUseNativeDialog , true ) ;
2014-07-08 03:11:14 -04:00
}
2015-12-31 16:41:59 -05:00
2014-07-08 03:11:14 -04:00
QString filename ;
//This must come first because it clears various internal states which allow the file text to be properly set.
//This is most likely a bug in QFileDialog.
m_FolderDialog - > setAcceptMode ( QFileDialog : : AcceptSave ) ;
m_FolderDialog - > setFileMode ( QFileDialog : : Directory ) ;
m_FolderDialog - > setOption ( QFileDialog : : ShowDirsOnly , true ) ;
m_FolderDialog - > setOption ( QFileDialog : : DontUseNativeDialog , true ) ;
m_FolderDialog - > selectFile ( " " ) ;
m_FolderDialog - > setWindowTitle ( " Save to folder " ) ;
m_FolderDialog - > setDirectory ( m_Settings - > SaveFolder ( ) ) ;
if ( m_FolderDialog - > exec ( ) = = QDialog : : Accepted )
2014-10-14 11:53:15 -04:00
{
filename = MakeEnd ( m_FolderDialog - > selectedFiles ( ) . value ( 0 ) , ' / ' ) ;
}
2014-07-08 03:11:14 -04:00
2017-04-04 19:21:58 -04:00
# else
auto filename = QFileDialog : : getExistingDirectory ( this , tr ( " Save to folder " ) ,
m_Settings - > SaveFolder ( ) ,
QFileDialog : : ShowDirsOnly | QFileDialog : : DontResolveSymlinks ) ;
if ( filename . size ( ) > 0 )
filename = MakeEnd ( filename , ' / ' ) ;
# endif
2014-07-08 03:11:14 -04:00
return filename ;
}
2014-10-14 11:53:15 -04:00
/// <summary>
/// Thin wrapper around QMessageBox::critical() to allow it to be invoked from another thread.
/// </summary>
2015-05-30 00:08:44 -04:00
/// <param name="title">The title of the message box</param>
/// <param name="text">The text displayed on the message box</param>
/// <param name="invokeRequired">True if running on another thread, else false. Default: false.</param>
2014-10-14 11:53:15 -04:00
void Fractorium : : ShowCritical ( const QString & title , const QString & text , bool invokeRequired )
{
if ( ! invokeRequired )
QMessageBox : : critical ( this , title , text ) ;
else
QMetaObject : : invokeMethod ( this , " ShowCritical " , Qt : : QueuedConnection , Q_ARG ( const QString & , title ) , Q_ARG ( const QString & , text ) , Q_ARG ( bool , false ) ) ;
}
2014-07-28 01:25:38 -04:00
/// <summary>
/// Explicitly set the tab orders for the entire program.
/// Qt has a facility to do this, but it fails when using custom widgets in
/// tables, so it must be done manually here.
/// This list must be kept in sync with any UI changes.
/// </summary>
void Fractorium : : SetTabOrders ( )
{
2016-06-11 20:47:03 -04:00
QWidget * w = SetTabOrder ( this , ui . ColorTable , m_BrightnessSpin ) ; //Flame color.
2014-07-28 01:25:38 -04:00
w = SetTabOrder ( this , w , m_GammaSpin ) ;
w = SetTabOrder ( this , w , m_GammaThresholdSpin ) ;
w = SetTabOrder ( this , w , m_VibrancySpin ) ;
w = SetTabOrder ( this , w , m_HighlightSpin ) ;
w = SetTabOrder ( this , w , m_BackgroundColorButton ) ;
w = SetTabOrder ( this , w , m_PaletteModeCombo ) ;
2016-06-11 20:47:03 -04:00
w = SetTabOrder ( this , w , m_WidthSpin ) ; //Flame geometry.
w = SetTabOrder ( this , w , m_HeightSpin ) ;
2014-07-28 01:25:38 -04:00
w = SetTabOrder ( this , w , m_CenterXSpin ) ;
w = SetTabOrder ( this , w , m_CenterYSpin ) ;
w = SetTabOrder ( this , w , m_ScaleSpin ) ;
w = SetTabOrder ( this , w , m_ZoomSpin ) ;
w = SetTabOrder ( this , w , m_RotateSpin ) ;
w = SetTabOrder ( this , w , m_ZPosSpin ) ;
w = SetTabOrder ( this , w , m_PerspectiveSpin ) ;
w = SetTabOrder ( this , w , m_PitchSpin ) ;
w = SetTabOrder ( this , w , m_YawSpin ) ;
w = SetTabOrder ( this , w , m_DepthBlurSpin ) ;
2016-06-11 20:47:03 -04:00
w = SetTabOrder ( this , w , m_SpatialFilterWidthSpin ) ; //Flame filter.
2014-07-28 01:25:38 -04:00
w = SetTabOrder ( this , w , m_SpatialFilterTypeCombo ) ;
w = SetTabOrder ( this , w , m_DEFilterMinRadiusSpin ) ;
w = SetTabOrder ( this , w , m_DEFilterMaxRadiusSpin ) ;
w = SetTabOrder ( this , w , m_DECurveSpin ) ;
2016-06-11 20:47:03 -04:00
w = SetTabOrder ( this , w , m_SbsSpin ) ; //Flame iteration.
w = SetTabOrder ( this , w , m_FuseSpin ) ;
2014-07-28 01:25:38 -04:00
w = SetTabOrder ( this , w , m_QualitySpin ) ;
w = SetTabOrder ( this , w , m_SupersampleSpin ) ;
2016-06-11 20:47:03 -04:00
w = SetTabOrder ( this , w , m_InterpTypeCombo ) ; //Flame animation.
2014-07-28 01:25:38 -04:00
w = SetTabOrder ( this , w , m_AffineInterpTypeCombo ) ;
2016-06-11 20:47:03 -04:00
w = SetTabOrder ( this , w , m_TemporalSamplesSpin ) ;
w = SetTabOrder ( this , w , m_TemporalFilterWidthSpin ) ;
w = SetTabOrder ( this , w , m_TemporalFilterTypeCombo ) ;
w = SetTabOrder ( this , ui . LibraryTree , ui . SequenceStartCountSpinBox ) ; //Library.
w = SetTabOrder ( this , w , ui . SequenceStartPreviewsButton ) ;
w = SetTabOrder ( this , w , ui . SequenceStopPreviewsButton ) ;
w = SetTabOrder ( this , w , ui . SequenceStartFlameSpinBox ) ;
w = SetTabOrder ( this , w , ui . SequenceStopFlameSpinBox ) ;
w = SetTabOrder ( this , w , ui . SequenceAllButton ) ;
w = SetTabOrder ( this , w , ui . SequenceRandomizeStaggerCheckBox ) ;
2016-06-11 22:01:19 -04:00
w = SetTabOrder ( this , w , ui . SequenceStaggerSpinBox ) ;
w = SetTabOrder ( this , w , ui . SequenceRandomStaggerMaxSpinBox ) ;
2016-06-11 20:47:03 -04:00
w = SetTabOrder ( this , w , ui . SequenceRandomizeRotationsCheckBox ) ;
w = SetTabOrder ( this , w , ui . SequenceRotationsSpinBox ) ;
--User changes
-Add a palette editor.
-Add support for reading .ugr/.gradient/.gradients palette files.
-Allow toggling on spinners whose minimum value is not zero.
-Allow toggling display of image, affines and grid.
-Add new variations: cylinder2, circlesplit, tile_log, truchet_fill, waves2_radial.
--Bug fixes
-cpow2 was wrong.
-Palettes with rapid changes in color would produce slightly different outputs from Apo/Chaotica. This was due to a long standing bug from flam3.
-Use exec() on Apple and show() on all other OSes for dialog boxes.
-Trying to render a sequence with no frames would crash.
-Selecting multiple xforms and rotating them would produce the wrong rotation.
-Better handling when parsing flames using different encoding, such as unicode and UTF-8.
-Switching between SP/DP didn't reselect the selected flame in the Library tab.
--Code changes
-Make all types concerning palettes be floats, including PaletteTableWidgetItem.
-PaletteTableWidgetItem is no longer templated because all palettes are float.
-Include the source colors for user created gradients.
-Change parallel_for() calls to work with very old versions of TBB which are lingering on some systems.
-Split conditional out of accumulation loop on the CPU for better performance.
-Vectorize summing when doing density filter for better performance.
-Make all usage of palettes be of type float, double is pointless.
-Allow palettes to reside in multiple folders, while ensuring only one of each name is added.
-Refactor some palette path searching code.
-Make ReadFile() throw and catch an exception if the file operation fails.
-A little extra safety in foci and foci3D with a call to Zeps().
-Cast to (real_t) in the OpenCL string for the w variation, which was having trouble compiling on Mac.
-Fixing missing comma between paths in InitPaletteList().
-Move Xml and PaletteList classes into cpp to shorten build times when working on them.
-Remove default param values for IterOpenCLKernelCreator<T>::SharedDataIndexDefines in cpp file.
-Change more NULL to nullptr.
2017-02-26 03:02:21 -05:00
w = SetTabOrder ( this , w , ui . SequenceRotationsCWCheckBox ) ;
2016-06-11 20:47:03 -04:00
w = SetTabOrder ( this , w , ui . SequenceRandomRotationsMaxSpinBox ) ;
--User changes
-Add a palette editor.
-Add support for reading .ugr/.gradient/.gradients palette files.
-Allow toggling on spinners whose minimum value is not zero.
-Allow toggling display of image, affines and grid.
-Add new variations: cylinder2, circlesplit, tile_log, truchet_fill, waves2_radial.
--Bug fixes
-cpow2 was wrong.
-Palettes with rapid changes in color would produce slightly different outputs from Apo/Chaotica. This was due to a long standing bug from flam3.
-Use exec() on Apple and show() on all other OSes for dialog boxes.
-Trying to render a sequence with no frames would crash.
-Selecting multiple xforms and rotating them would produce the wrong rotation.
-Better handling when parsing flames using different encoding, such as unicode and UTF-8.
-Switching between SP/DP didn't reselect the selected flame in the Library tab.
--Code changes
-Make all types concerning palettes be floats, including PaletteTableWidgetItem.
-PaletteTableWidgetItem is no longer templated because all palettes are float.
-Include the source colors for user created gradients.
-Change parallel_for() calls to work with very old versions of TBB which are lingering on some systems.
-Split conditional out of accumulation loop on the CPU for better performance.
-Vectorize summing when doing density filter for better performance.
-Make all usage of palettes be of type float, double is pointless.
-Allow palettes to reside in multiple folders, while ensuring only one of each name is added.
-Refactor some palette path searching code.
-Make ReadFile() throw and catch an exception if the file operation fails.
-A little extra safety in foci and foci3D with a call to Zeps().
-Cast to (real_t) in the OpenCL string for the w variation, which was having trouble compiling on Mac.
-Fixing missing comma between paths in InitPaletteList().
-Move Xml and PaletteList classes into cpp to shorten build times when working on them.
-Remove default param values for IterOpenCLKernelCreator<T>::SharedDataIndexDefines in cpp file.
-Change more NULL to nullptr.
2017-02-26 03:02:21 -05:00
w = SetTabOrder ( this , w , ui . SequenceRandomizeFramesPerRotCheckBox ) ;
w = SetTabOrder ( this , w , ui . SequenceFramesPerRotSpinBox ) ;
w = SetTabOrder ( this , w , ui . SequenceRandomFramesPerRotMaxSpinBox ) ;
2016-06-11 20:47:03 -04:00
w = SetTabOrder ( this , w , ui . SequenceRandomizeBlendFramesCheckBox ) ;
w = SetTabOrder ( this , w , ui . SequenceBlendFramesSpinBox ) ;
w = SetTabOrder ( this , w , ui . SequenceRandomBlendMaxFramesSpinBox ) ;
--User changes
-Add a palette editor.
-Add support for reading .ugr/.gradient/.gradients palette files.
-Allow toggling on spinners whose minimum value is not zero.
-Allow toggling display of image, affines and grid.
-Add new variations: cylinder2, circlesplit, tile_log, truchet_fill, waves2_radial.
--Bug fixes
-cpow2 was wrong.
-Palettes with rapid changes in color would produce slightly different outputs from Apo/Chaotica. This was due to a long standing bug from flam3.
-Use exec() on Apple and show() on all other OSes for dialog boxes.
-Trying to render a sequence with no frames would crash.
-Selecting multiple xforms and rotating them would produce the wrong rotation.
-Better handling when parsing flames using different encoding, such as unicode and UTF-8.
-Switching between SP/DP didn't reselect the selected flame in the Library tab.
--Code changes
-Make all types concerning palettes be floats, including PaletteTableWidgetItem.
-PaletteTableWidgetItem is no longer templated because all palettes are float.
-Include the source colors for user created gradients.
-Change parallel_for() calls to work with very old versions of TBB which are lingering on some systems.
-Split conditional out of accumulation loop on the CPU for better performance.
-Vectorize summing when doing density filter for better performance.
-Make all usage of palettes be of type float, double is pointless.
-Allow palettes to reside in multiple folders, while ensuring only one of each name is added.
-Refactor some palette path searching code.
-Make ReadFile() throw and catch an exception if the file operation fails.
-A little extra safety in foci and foci3D with a call to Zeps().
-Cast to (real_t) in the OpenCL string for the w variation, which was having trouble compiling on Mac.
-Fixing missing comma between paths in InitPaletteList().
-Move Xml and PaletteList classes into cpp to shorten build times when working on them.
-Remove default param values for IterOpenCLKernelCreator<T>::SharedDataIndexDefines in cpp file.
-Change more NULL to nullptr.
2017-02-26 03:02:21 -05:00
w = SetTabOrder ( this , w , ui . SequenceRandomizeRotationsPerBlendCheckBox ) ;
w = SetTabOrder ( this , w , ui . SequenceRotationsPerBlendSpinBox ) ;
w = SetTabOrder ( this , w , ui . SequenceRotationsPerBlendCWCheckBox ) ;
w = SetTabOrder ( this , w , ui . SequenceRotationsPerBlendMaxSpinBox ) ;
2016-06-11 20:47:03 -04:00
w = SetTabOrder ( this , w , ui . SequenceGenerateButton ) ;
w = SetTabOrder ( this , w , ui . SequenceRenderButton ) ;
w = SetTabOrder ( this , w , ui . SequenceSaveButton ) ;
w = SetTabOrder ( this , w , ui . SequenceOpenButton ) ;
w = SetTabOrder ( this , w , ui . SequenceTree ) ;
2014-07-28 01:25:38 -04:00
w = SetTabOrder ( this , ui . CurrentXformCombo , ui . AddXformButton ) ; //Xforms.
2016-06-11 20:47:03 -04:00
w = SetTabOrder ( this , w , ui . AddLinkedXformButton ) ;
2014-07-28 01:25:38 -04:00
w = SetTabOrder ( this , w , ui . DuplicateXformButton ) ;
w = SetTabOrder ( this , w , ui . ClearXformButton ) ;
w = SetTabOrder ( this , w , ui . DeleteXformButton ) ;
w = SetTabOrder ( this , w , ui . AddFinalXformButton ) ;
w = SetTabOrder ( this , w , m_XformWeightSpin ) ;
w = SetTabOrder ( this , w , m_XformWeightSpinnerButtonWidget - > m_Button ) ;
w = SetTabOrder ( this , m_XformColorIndexSpin , ui . XformColorScroll ) ; //Xforms color.
2016-06-11 20:47:03 -04:00
w = SetTabOrder ( this , w , ui . RandomColorIndicesButton ) ;
w = SetTabOrder ( this , w , ui . ToggleColorIndicesButton ) ;
2014-07-28 01:25:38 -04:00
w = SetTabOrder ( this , w , m_XformColorSpeedSpin ) ;
w = SetTabOrder ( this , w , m_XformOpacitySpin ) ;
w = SetTabOrder ( this , w , m_XformDirectColorSpin ) ;
w = SetTabOrder ( this , w , ui . SoloXformCheckBox ) ;
2016-06-11 20:47:03 -04:00
w = SetTabOrder ( this , w , m_PreX1Spin ) ;
2014-07-28 01:25:38 -04:00
w = SetTabOrder ( this , w , m_PreX2Spin ) ;
w = SetTabOrder ( this , w , m_PreY1Spin ) ;
w = SetTabOrder ( this , w , m_PreY2Spin ) ;
w = SetTabOrder ( this , w , m_PreO1Spin ) ;
w = SetTabOrder ( this , w , m_PreO2Spin ) ;
w = SetTabOrder ( this , w , ui . PreFlipVerticalButton ) ;
2018-09-15 06:11:12 -04:00
w = SetTabOrder ( this , w , ui . PreCopyButton ) ;
2014-07-28 01:25:38 -04:00
w = SetTabOrder ( this , w , ui . PreResetButton ) ;
2018-09-15 06:11:12 -04:00
w = SetTabOrder ( this , w , ui . PrePasteButton ) ;
2014-07-28 01:25:38 -04:00
w = SetTabOrder ( this , w , ui . PreFlipHorizontalButton ) ;
w = SetTabOrder ( this , w , ui . PreRotate90CcButton ) ;
w = SetTabOrder ( this , w , ui . PreRotateCcButton ) ;
w = SetTabOrder ( this , w , ui . PreRotateCombo ) ;
w = SetTabOrder ( this , w , ui . PreRotateCButton ) ;
w = SetTabOrder ( this , w , ui . PreRotate90CButton ) ;
w = SetTabOrder ( this , w , ui . PreMoveUpButton ) ;
w = SetTabOrder ( this , w , ui . PreMoveDownButton ) ;
w = SetTabOrder ( this , w , ui . PreMoveCombo ) ;
w = SetTabOrder ( this , w , ui . PreMoveLeftButton ) ;
w = SetTabOrder ( this , w , ui . PreMoveRightButton ) ;
w = SetTabOrder ( this , w , ui . PreScaleDownButton ) ;
2015-06-20 14:35:08 -04:00
w = SetTabOrder ( this , w , ui . PreScaleCombo ) ;
w = SetTabOrder ( this , w , ui . PreScaleUpButton ) ;
2016-06-11 20:47:03 -04:00
w = SetTabOrder ( this , w , ui . PreRandomButton ) ;
2014-07-28 01:25:38 -04:00
w = SetTabOrder ( this , w , ui . ShowPreAffineCurrentRadio ) ;
w = SetTabOrder ( this , w , ui . ShowPreAffineAllRadio ) ;
2018-09-30 17:20:02 -04:00
w = SetTabOrder ( this , w , ui . SwapAffinesButton ) ;
2014-07-28 01:25:38 -04:00
w = SetTabOrder ( this , w , ui . PostAffineGroupBox ) ;
w = SetTabOrder ( this , w , m_PostX1Spin ) ;
w = SetTabOrder ( this , w , m_PostX2Spin ) ;
w = SetTabOrder ( this , w , m_PostY1Spin ) ;
w = SetTabOrder ( this , w , m_PostY2Spin ) ;
w = SetTabOrder ( this , w , m_PostO1Spin ) ;
w = SetTabOrder ( this , w , m_PostO2Spin ) ;
w = SetTabOrder ( this , w , ui . PostFlipVerticalButton ) ;
2018-09-15 06:11:12 -04:00
w = SetTabOrder ( this , w , ui . PostCopyButton ) ;
2014-07-28 01:25:38 -04:00
w = SetTabOrder ( this , w , ui . PostResetButton ) ;
2018-09-15 06:11:12 -04:00
w = SetTabOrder ( this , w , ui . PostPasteButton ) ;
2014-07-28 01:25:38 -04:00
w = SetTabOrder ( this , w , ui . PostFlipHorizontalButton ) ;
w = SetTabOrder ( this , w , ui . PostRotate90CcButton ) ;
w = SetTabOrder ( this , w , ui . PostRotateCcButton ) ;
w = SetTabOrder ( this , w , ui . PostRotateCombo ) ;
w = SetTabOrder ( this , w , ui . PostRotateCButton ) ;
w = SetTabOrder ( this , w , ui . PostRotate90CButton ) ;
w = SetTabOrder ( this , w , ui . PostMoveUpButton ) ;
w = SetTabOrder ( this , w , ui . PostMoveDownButton ) ;
w = SetTabOrder ( this , w , ui . PostMoveCombo ) ;
w = SetTabOrder ( this , w , ui . PostMoveLeftButton ) ;
w = SetTabOrder ( this , w , ui . PostMoveRightButton ) ;
w = SetTabOrder ( this , w , ui . PostScaleDownButton ) ;
2015-06-20 14:35:08 -04:00
w = SetTabOrder ( this , w , ui . PostScaleCombo ) ;
w = SetTabOrder ( this , w , ui . PostScaleUpButton ) ;
2016-06-11 20:47:03 -04:00
w = SetTabOrder ( this , w , ui . PostRandomButton ) ;
2014-07-28 01:25:38 -04:00
w = SetTabOrder ( this , w , ui . ShowPostAffineCurrentRadio ) ;
w = SetTabOrder ( this , w , ui . ShowPostAffineAllRadio ) ;
2016-06-11 20:47:03 -04:00
w = SetTabOrder ( this , w , ui . PolarAffineCheckBox ) ;
2014-07-28 01:25:38 -04:00
w = SetTabOrder ( this , w , ui . LocalPivotRadio ) ;
w = SetTabOrder ( this , w , ui . WorldPivotRadio ) ;
w = SetTabOrder ( this , ui . VariationsFilterLineEdit , ui . VariationsFilterClearButton ) ; //Xforms variation.
w = SetTabOrder ( this , w , ui . VariationsTree ) ;
2018-07-31 00:39:41 -04:00
w = SetTabOrder ( this , w , ui . ClearXaosButton ) ;
w = SetTabOrder ( this , w , ui . RandomXaosButton ) ;
w = SetTabOrder ( this , w , ui . AddLayerButton ) ;
w = SetTabOrder ( this , w , ui . AddLayerSpinBox ) ;
2014-07-28 01:25:38 -04:00
//Xforms xaos is done dynamically every time.
2016-06-11 20:47:03 -04:00
w = SetTabOrder ( this , ui . PaletteFilenameCombo , m_PaletteHueSpin ) ; //Palette.
w = SetTabOrder ( this , w , m_PaletteContrastSpin ) ;
2014-07-28 01:25:38 -04:00
w = SetTabOrder ( this , w , m_PaletteSaturationSpin ) ;
w = SetTabOrder ( this , w , m_PaletteBlurSpin ) ;
w = SetTabOrder ( this , w , m_PaletteBrightnessSpin ) ;
w = SetTabOrder ( this , w , m_PaletteFrequencySpin ) ;
--User changes
-Add a palette editor.
-Add support for reading .ugr/.gradient/.gradients palette files.
-Allow toggling on spinners whose minimum value is not zero.
-Allow toggling display of image, affines and grid.
-Add new variations: cylinder2, circlesplit, tile_log, truchet_fill, waves2_radial.
--Bug fixes
-cpow2 was wrong.
-Palettes with rapid changes in color would produce slightly different outputs from Apo/Chaotica. This was due to a long standing bug from flam3.
-Use exec() on Apple and show() on all other OSes for dialog boxes.
-Trying to render a sequence with no frames would crash.
-Selecting multiple xforms and rotating them would produce the wrong rotation.
-Better handling when parsing flames using different encoding, such as unicode and UTF-8.
-Switching between SP/DP didn't reselect the selected flame in the Library tab.
--Code changes
-Make all types concerning palettes be floats, including PaletteTableWidgetItem.
-PaletteTableWidgetItem is no longer templated because all palettes are float.
-Include the source colors for user created gradients.
-Change parallel_for() calls to work with very old versions of TBB which are lingering on some systems.
-Split conditional out of accumulation loop on the CPU for better performance.
-Vectorize summing when doing density filter for better performance.
-Make all usage of palettes be of type float, double is pointless.
-Allow palettes to reside in multiple folders, while ensuring only one of each name is added.
-Refactor some palette path searching code.
-Make ReadFile() throw and catch an exception if the file operation fails.
-A little extra safety in foci and foci3D with a call to Zeps().
-Cast to (real_t) in the OpenCL string for the w variation, which was having trouble compiling on Mac.
-Fixing missing comma between paths in InitPaletteList().
-Move Xml and PaletteList classes into cpp to shorten build times when working on them.
-Remove default param values for IterOpenCLKernelCreator<T>::SharedDataIndexDefines in cpp file.
-Change more NULL to nullptr.
2017-02-26 03:02:21 -05:00
w = SetTabOrder ( this , w , ui . PaletteRandomSelectButton ) ;
w = SetTabOrder ( this , w , ui . PaletteRandomAdjustButton ) ;
w = SetTabOrder ( this , w , ui . PaletteEditorButton ) ;
2015-06-17 23:05:53 -04:00
w = SetTabOrder ( this , w , ui . PaletteFilterLineEdit ) ;
w = SetTabOrder ( this , w , ui . PaletteFilterClearButton ) ;
2014-07-28 01:25:38 -04:00
w = SetTabOrder ( this , w , ui . PaletteListTable ) ;
2016-06-11 20:47:03 -04:00
w = SetTabOrder ( this , w , ui . ResetCurvesButton ) ; //Palette curves.
w = SetTabOrder ( this , w , ui . CurvesView ) ;
w = SetTabOrder ( this , w , ui . CurvesGroupBox ) ;
w = SetTabOrder ( this , w , ui . CurvesAllRadio ) ;
w = SetTabOrder ( this , w , ui . CurvesRedRadio ) ;
w = SetTabOrder ( this , w , ui . CurvesGreenRadio ) ;
w = SetTabOrder ( this , w , ui . CurvesBlueRadio ) ;
2015-10-27 00:31:35 -04:00
w = SetTabOrder ( this , ui . SummaryTable , ui . SummaryTree ) ; //Info summary.
2015-07-15 23:27:32 -04:00
w = SetTabOrder ( this , ui . InfoBoundsGroupBox , ui . InfoBoundsFrame ) ; //Info bounds.
2014-07-28 01:25:38 -04:00
w = SetTabOrder ( this , w , ui . InfoBoundsTable ) ;
w = SetTabOrder ( this , w , ui . InfoFileOpeningGroupBox ) ;
w = SetTabOrder ( this , w , ui . InfoFileOpeningTextEdit ) ;
w = SetTabOrder ( this , w , ui . InfoRenderingGroupBox ) ;
w = SetTabOrder ( this , w , ui . InfoRenderingTextEdit ) ;
}
2015-05-15 21:45:15 -04:00
/// <summary>
/// Toggle all table spinner values in one row.
/// The logic is:
/// If any cell in the row is non zero, set all cells to zero, else 1.
/// If shift is held down, reverse the logic.
/// Resets the rendering process.
/// </summary>
2015-05-30 00:08:44 -04:00
/// <param name="table">The QTableWidget or QTableView whose row will be toggled</param>
2015-05-15 21:45:15 -04:00
/// <param name="logicalIndex">The index of the row that was double clicked</param>
2015-05-30 00:08:44 -04:00
void Fractorium : : ToggleTableRow ( QTableView * table , int logicalIndex )
2015-05-15 21:45:15 -04:00
{
bool allZero = true ;
2015-05-30 00:08:44 -04:00
auto model = table - > model ( ) ;
int cols = model - > columnCount ( ) ;
2015-05-15 21:45:15 -04:00
bool shift = QGuiApplication : : keyboardModifiers ( ) . testFlag ( Qt : : ShiftModifier ) ;
2015-07-23 21:16:36 -04:00
auto tableWidget = qobject_cast < QTableWidget * > ( table ) ;
2015-05-15 21:45:15 -04:00
2015-05-30 00:08:44 -04:00
if ( tableWidget )
2015-05-15 21:45:15 -04:00
{
2015-05-30 00:08:44 -04:00
for ( int i = 0 ; i < cols ; i + + )
2015-05-15 21:45:15 -04:00
{
2016-02-20 21:44:52 -05:00
if ( auto spinBox = qobject_cast < DoubleSpinBox * > ( tableWidget - > cellWidget ( logicalIndex , i ) ) )
2015-05-30 00:08:44 -04:00
{
if ( ! IsNearZero ( spinBox - > value ( ) ) )
{
allZero = false ;
break ;
}
}
}
if ( shift )
allZero = ! allZero ;
double val = allZero ? 1.0 : 0.0 ;
for ( int i = 0 ; i < cols ; i + + )
2016-02-20 21:44:52 -05:00
if ( auto spinBox = qobject_cast < DoubleSpinBox * > ( tableWidget - > cellWidget ( logicalIndex , i ) ) )
2015-05-30 00:08:44 -04:00
spinBox - > setValue ( val ) ;
}
else
{
for ( int i = 0 ; i < cols ; i + + )
{
if ( ! IsNearZero ( model - > data ( model - > index ( logicalIndex , i , QModelIndex ( ) ) ) . toDouble ( ) ) )
2015-05-15 21:45:15 -04:00
{
allZero = false ;
break ;
}
}
2015-05-30 00:08:44 -04:00
if ( shift )
allZero = ! allZero ;
2015-05-15 21:45:15 -04:00
2015-05-30 00:08:44 -04:00
double val = allZero ? 1.0 : 0.0 ;
2015-05-15 21:45:15 -04:00
2015-05-30 00:08:44 -04:00
for ( int i = 0 ; i < cols ; i + + )
model - > setData ( model - > index ( logicalIndex , i ) , val , Qt : : EditRole ) ;
}
2015-05-15 21:45:15 -04:00
}
/// <summary>
/// Toggle all table spinner values in one column.
/// The logic is:
/// If any cell in the column is non zero, set all cells to zero, else 1.
/// If shift is held down, reverse the logic.
/// Resets the rendering process.
/// </summary>
2015-05-30 00:08:44 -04:00
/// <param name="table">The QTableWidget or QTableView whose column will be toggled</param>
2015-05-15 21:45:15 -04:00
/// <param name="logicalIndex">The index of the column that was double clicked</param>
2015-05-30 00:08:44 -04:00
void Fractorium : : ToggleTableCol ( QTableView * table , int logicalIndex )
2015-05-15 21:45:15 -04:00
{
bool allZero = true ;
2015-05-30 00:08:44 -04:00
auto model = table - > model ( ) ;
int rows = model - > rowCount ( ) ;
2015-05-15 21:45:15 -04:00
bool shift = QGuiApplication : : keyboardModifiers ( ) . testFlag ( Qt : : ShiftModifier ) ;
2015-07-23 21:16:36 -04:00
auto tableWidget = qobject_cast < QTableWidget * > ( table ) ;
2015-05-15 21:45:15 -04:00
2015-05-30 00:08:44 -04:00
if ( tableWidget )
2015-05-15 21:45:15 -04:00
{
2015-05-30 00:08:44 -04:00
for ( int i = 0 ; i < rows ; i + + )
2015-05-15 21:45:15 -04:00
{
2016-02-20 21:44:52 -05:00
if ( auto spinBox = qobject_cast < DoubleSpinBox * > ( tableWidget - > cellWidget ( i , logicalIndex ) ) )
2015-05-15 21:45:15 -04:00
{
2015-05-30 00:08:44 -04:00
if ( ! IsNearZero ( spinBox - > value ( ) ) )
{
allZero = false ;
break ;
}
2015-05-15 21:45:15 -04:00
}
}
2015-05-30 00:08:44 -04:00
if ( shift )
allZero = ! allZero ;
2015-05-15 21:45:15 -04:00
2015-05-30 00:08:44 -04:00
double val = allZero ? 1.0 : 0.0 ;
2015-05-15 21:45:15 -04:00
2015-05-30 00:08:44 -04:00
for ( int i = 0 ; i < rows ; i + + )
2016-02-20 21:44:52 -05:00
if ( auto spinBox = qobject_cast < DoubleSpinBox * > ( tableWidget - > cellWidget ( i , logicalIndex ) ) )
2015-05-30 00:08:44 -04:00
spinBox - > setValue ( val ) ;
}
else
{
for ( int i = 0 ; i < rows ; i + + )
{
if ( ! IsNearZero ( model - > data ( model - > index ( i , logicalIndex , QModelIndex ( ) ) ) . toDouble ( ) ) )
{
allZero = false ;
break ;
}
}
2015-05-15 21:45:15 -04:00
2015-05-30 00:08:44 -04:00
if ( shift )
allZero = ! allZero ;
2014-07-08 03:11:14 -04:00
2015-05-30 00:08:44 -04:00
double val = allZero ? 1.0 : 0.0 ;
2014-07-08 03:11:14 -04:00
2015-05-30 00:08:44 -04:00
for ( int i = 0 ; i < rows ; i + + )
model - > setData ( model - > index ( i , logicalIndex ) , val , Qt : : EditRole ) ;
}
2014-07-08 03:11:14 -04:00
}
2014-12-11 00:50:15 -05:00
template class FractoriumEmberController < float > ;
# ifdef DO_DOUBLE
template class FractoriumEmberController < double > ;
# endif